/*
 *	recorder9_collide.c 
 *
 *	model a recorder
 *	12-21-11
 *
 *	usage: recorder4
 *		in this case results are written to a subdirectory named "results"
 *	or
 *	usage: recorder4 dir
 *		in this case results are written to a subdirectory named "dir"
 *	or
 *	usage: recorder4 -h
 *		to get help with command line args
 *
 *	usage: recorder4 -restart dir
 *		reads map data and time from files and continues a previous calc 
 *		the files are t_restart", rho_map_restart, u_map_restart, and v_map_restart
 *		 
 *	usage: recorder4 test
 *		generates the geometry file and then exits
 *
 *	NOTE: see below (after recorder7a) for major changes in the command line
 *
 *	2D simulation
 *	use explicit MacCormack method
 *
 *	v3 uses nonslip boundary conditions for the recorder surfaces
 *	and absorbing boundaries at the walls of the region
 *
 *	this version is prepared for amdahl 01-03-12
 *		- found some mistakes in the version running the past
 *		few days on my laptop, but those results are still ok
 *
 *	v4 adds second order artifical viscosity as described by Kuruvila and Anderson
 *	
 *	v5 adds fourth order viscosity patterned roughly after Jameson
 *
 *	v6 makes the second and fourth order viscosity follow Jameson more closely (with
 *		a switch of the 4th order term), but not exactly
 *
 *	v6b follow the Jameson-Turkel relations exactly, except near boundaries where
 *		there is only 2nd order dissipation
 * 
 *	v6c add the ability to turn ramp blowing speed to zero at end of a tone
 *
 *	v6d change the boundary conditions at the outer edges -- use an impedance
 *		Z = Z_1 + i omega Z_2
 *
 *	v6e same as v6d but change the way I numerically implement that impedance 
 *		condition at the edges of the boundary
 *
 *	v6f add the ability to filter out high frequencies by periodically time averaging the spatial
 *		maps of rho, u, and v
 *		the averaging will be specified by 3 parameters:
 *			t_accum = time period to accumulate data for averaging 
 *			t_accum_interval = how often to accum for filtering (t_accum_interval > t_accum)
 *			t_accum_start = when to start accumulating 
 *
 *	v6g add a flag so that can toggle boundary condition on simulation region between having
 *		an impedance Z or having rho = u = v = 0 (as in v6c and previous)
 *		make a few small tweaks to filtering routines on 3-11-12
 *
 *	v7a -- still 2D but now allow for a nonuniform cartesian grid
 *		The initialization files now change a bit
 *		run_data.dat is unchanged - it contains all the non-geometry information
 *		The geometry files are generated by a pre-processing programm geometry_setup.c
 *		The grid information is stored in files x_grid.dat and y_grid.dat
 *			The format for these files is
 *			i1	x1	dx1
 *			i2	x2	dx2
 *			etc. for the rest of the x file and for y
 *			where i1 is the grid index, dx1 is the distance between grid points i1 and i2
 *			and x1 is the absolute location of grid index point i1
 *
 *		The spatial grid/geometry is stored in three files:
 *			geometry_solid.dat contains all the points on the boundary and in and on the recorder
 *			geometry_initialize.dat contains points where u is imposed (initialized) in the channel
 *			geometry_record.dat contains the three points where the sound is recorded
 *			The format for all of these files is in terms of grid indices
 *				i1	j1
 *				i2	j2
 *				etc.
 *			The actual spatial location of these points can then be found from the grid info
 *			in x_grid.dat and y_grid.dat
 *
 *		The initialization info for u in the channel is stored in u_init.dat
 *			The format is just one line with the values of u starting at the lower edge of the
 *			channel and proceeding to the upper edge
 *
 *		The files x_grid.dat, y_grid.dat, geometry_solid.dat, geometry_initialize.dat, geometry_sound.dat
 *			and u_init.dat are all found in a directory (<input_directory>) named on the
 *			argument line of recorder7a.
 *
 *		The other information needed is run_data.dat which is taken from the current directory
 *			Files needed for a restart (t_restart, rho_map_restart, u_map_restart, and v_map_restart)
 *			are also read from the current directory
 *
 *		All output files are written to the <output_directory>
 *
 *		NEW USAGE:
 *			recorder7a
 *			or
 *			recorder7a input_directory output_directory
 *			or
 *			recorder7a -restart input_directory output_directory
 *
 *			with no command line arguments gives just the usage information
 *
 *			input_directory = directory from which all the input files are read
 *			including the geometry, the blowing conditions, and restart information (if needed)
 *
 *			-restart indicates that this is a continuation of a previous run
 *
 *			output_directory = directory into which all the output files are written
 *
 *	recorder8:	start work on three dimensional version		
 *			this test version is still 2D, but I am cutting back on the number of arrays
 *			and their sizes - once this is tested I will move on to 3D
 *
 *			note a major change to the way the map files for rho, u, v, and w are saved
 *			all of the info is now in one file rather than in separate files
 *
 *			there are other big changes necessitated by going to 3 dimensions
 *
 *		usage:
 *			recorder8 input_directory master_output_directory runxxx
 *			or
 *			recorder8 -restart input_directory master_output_directory runxxx
 *
 *			input_directory holds input grid data and run data
 *			master_output_directory is the parent directory that holds the output from
 *				each run -- each run is in directory runxxx where xxx is the run number
 *			
 *			for a restart the starting time is read from the file t_restart (in current dir)
 *			and the starting map data is read from a SINGLE file restart_maps.dat
 *			that is in the $RCAC_SCRATCH directory 
 *
 *			note map data for restarts and map data for observing spatial variation of
 *			rho, u, v, and w are now saved in the scratch directory and data for a 
 *			given time is stored in a single file (not in separate files as in the past)
 *
 *	recorder8.2:	add capability to incorporate a surface normal vector at the surface of the
 *			instrument that is not simply perpendicular - this is hoped to be good for
 *			dealing with corners and edges to allow for a flaring horn, etc.
 *
 *			surface normal data is in the input directory with the name surface_point_info.dat
 *			and is stored in a table with the form 
 *			i	j	k	i_hat	j_hat	k_hat
 *
 *			if this file is not found in the input directory then the old way of dealing with
 *			the instrument surface is used
 *			 
 *	recorder8.3	found a bug in the way the surface normal info is treated
 *
 *	recorder9	add flexible lips to model trumpet
 *
 *	recorder9_collide	allow lips to collide
 */

#include "recorder9.h"	/* general defines	*/

double blowing_velocity();
double artificial_viscosity();
double artificial_viscosity_on_recorder();
double artificial_viscosity_on_boundary();
double artificial_viscosity_on_lips();
double bigger();
double second_deriv_x();
double second_deriv_y();
double second_deriv_z();
double reset_filtering_data();

double avoid_j_contact();

int find_ghost_sites();
int nearest_int();

double i_leading_edge();
double i_trailing_edge();
double i_leading_edge_double();
double i_trailing_edge_double();

int i_mid_lip();
int i_entrance_lip();
int i_exit_lip();
int i_upstream_lip_middle();
int i_downstream_lip_middle();

float ***allocate_array_of_floats();
int ***allocate_array_of_integers();

float ***rho,***rho_predictor;

float ***rho_ave,***u_ave,***v_ave,***w_ave;

				/* current x and y components of velocity */
float ***u,***v,***w;

float ***u_predictor,***v_predictor,***w_predictor;

float ***u_pred_pred,***v_pred_pred,***w_pred_pred,***rho_pred_pred;

float ***rho_buf,***u_buf,***v_buf,***w_buf;

int i_min, i_max;	/* these are the boundaries of rectangular simulation region	*/
int j_min, j_max;	/* i_min = j_min = k_min = 0 and the other boundaries are at	*/
int k_min, k_max;	/* i_max, j_max and k_max					*/

int i_init_min,i_init_max;	/* range of indices for the initialization region	*/
int j_init_min,j_init_max;
int k_init_min,k_init_max;
double init_val_j[N_Y_MAX]; /* used for initialization - typically have poiselle-like flow  */
double init_val_k[N_Z_MAX]; /* used for initialization - typically have poiselle-like flow  */
			/* in a channel	*/

double t,dt;		/* t = time and dt = time step */
double dx_min;		/* smallest grid spacing along x or y	*/
double nu;	/* kinematic viscosity		*/
double c_s;	/* speed of sound in air	*/
double rho_air;	/* density of air		*/
double courant; /* factor relating dt, dx_min, and c_s	*/
/* most of these values (nu, c_s, rho_air, etc.) are set in run_data.dat	*/

double t_start,t_end;	/* t_start = 0 = time that simulation starts (unless this run */
			/* is a restart), t_end = end	*/
double t_stop_blowing,t_ramp_down;	/* time to start ramping down the blowing	*/
			/* speed and time to take to ramp blowing speed to zero		*/
double t_record_map;	/* how often to record full results for rho, u, and v as functions */
			/* of position - for later analysis				*/
double t_map_ave;	/* average map data over this interval before saving	*/
double t_map_start;	/* when to start taking map data			*/
double t_map_end;	/* when to stop taking map data			*/
double t_record_sound;  /* how often to record rho vs. t at two listening points	*/

double u_init,v_init;	/* initialization values of u and v in specified region		*/
			/* in v3 -- v7 this region is rectangular and v_init is assumed to be 0 */

// will be accessed by geometry[i][j][k];	
int ***geometry;		/* describes the domain of the calc */
			/* the geometry (including the shape of the recorder)	*/
			/* is specified in the files geometry_solid.dat, geometry_initialization.dat*/
 			/* and geometry_sound.dat		*/
			/* in geometry[][][] OPEN = open space away from walls	*/
			/* SOLID = body of recorder		*/
			/* for other values see recorder8.h	*/

FILE *fp_t;	/* use this file to store the time at which maps 
			density and velocity vs position data are strored */

int i_record[21],j_record[21];	/* record rho vs. time at	*/
int k_record[21];	/* several different locations (currently max of 20)  specified in geometry_sound.dat	*/
int n_record_sound;	/* number of places to record the sound	and v_x=u	*/

double rho_t_sum[21]; 		/* use to average rho at the locations for intervals */
double vel_t_sum[21]; 		/* use to average rho at the locations for intervals */
double t_sum;			/* for averaging the time to go along with rho_t_*_sum	*/
double lip_force_y_sum[2],lip_force_x_sum[2];

char master_output_directory[300];
char results_directory[300];	/* directory in which all results are written - typically named runxxx 
					where xxx is a number		*/
int n_boundary;			/* number of boundary points on the recorder */
int x_boundary[N_MAX_3];	/* all points on the boundary of the recorder are stored */
int y_boundary[N_MAX_3];	/* in these three arrays (the i,j,k indices)		*/
int z_boundary[N_MAX_3];	/* in these three arrays (the i,j,k indices)		*/
int boundary_flag[N_MAX_3];	/* this flag specified what kind of boundary it is	*/
				/* this determines how it is dealt with -- to achieve	*/
				/* non-slip boundary conditions with acoustic impedance Z */
double Z_rec_1,Z_rec_2;		/* acoustic impedance of recorder surface rho = (Z_rec_1 + i omega Z_rec_2)*v_n/c^2*/
double Z_rec_1_norm;		/* define Z_rec_norm = Z / c^2	for convenience		*/
double Z_rec_2_norm;
double Z_rec_2_prime;		/* Z_2 normalized differently			*/
double Z_rec_1_2_plus;

double Z_bound_1,Z_bound_2;	/* acoustic impedance of the outer boundaries	*/
double Z_bound_1_norm,Z_bound_2_norm;	/* same as Z_rec_norm above		*/
double Z_bound_2_prime;		/* Z_2 normalized differently			*/
double Z_bound_1_2_plus;

int restart_flag;	/* = START_FRESH for a new calc, RE_START to continue a previous calc	*/
double t_restart_save_interval;	/* save things this often for poossible restart */
char restart_maps[300];	/* file names for restart info			*/

FILE *fp_log;	/* use to log info from each run	*/

double viscosity_1_0,viscosity_2_0;/* parameters determining the magnitude of	*/
				/* the artificial viscosity			*/
double t_viscosity_start;	/* time to turn on the artificial viscosity	*/

double t_blow_transient;	/* time to ramp up channel velocity		*/

int n_viscosity_monitor;	/* used for debugging				*/

double t_accum;			/* time period to accum map data to damp noise issues at high frequencies */
double t_accum_interval;	/* how often to average (t_average_interval > t_map_average)		*/
double t_accum_start;		/* when to start this averaging						*/

int boundary_Z_flag;		/* = ON means use the above values of Z for boundaries of simulation region */
				/* = OFF means set rho = u = v = 0 on boundaries	*/

double dx_grid[N_X_MAX],dy_grid[N_Y_MAX],dz_grid[N_Z_MAX];	/* grid spacings along x and y -- 
						note that dx[i] is the spacing between points i and i+1	*/
double x_grid[N_X_MAX],y_grid[N_Y_MAX],z_grid[N_Z_MAX];	/* locations in real space of grid points i,j,k	*/

char input_directory[400];
char scratch_directory[400];
char results_directory_full_path[400];

//	variables holding surface normal info
// i,j,k coordinates of all surface points
int i_surface[N_MAX_3],j_surface[N_MAX_3],k_surface[N_MAX_3]; 
double x_hat[N_MAX_3],y_hat[N_MAX_3],z_hat[N_MAX_3]; // unit vector normal to surface
int n_surface_points;	// number of surface points
int surface_normal_flag;	// = YES if this data is available

//	lip variables
int i_corner[2],j_corner[2];
double i_origin[2],j_origin[2]; // origin positions of lips, LEFT or RIGHT
int i_pivot[2],j_pivot[2];

double i_width[2],j_width[2];
double di_center[3][4],dj_center[3][4]; // first index: LEFT or RIGHT, second NEW, OLD, CURRENT
double i_center[3][4],j_center[3][4];   // first index: LEFT or RIGHT, second NEW, OLD, CURRENT

double j_center_interior[3][4],dj_center_interior[3][4]; // first index: LEFT or RIGHT, second NEW, OLD, CURRENT
double i_center_interior[3][4],di_center_interior[3][4]; // first index: LEFT or RIGHT, second NEW, OLD, CURRENT

int i_lip_region_max,i_lip_region_min;	// used to reduce loop area when dealing with lips
int j_lip_region_max,j_lip_region_min;
int k_lip_region_max,k_lip_region_min;

int i_corner[2],j_corner[2],k_corner[2];

// data for lip mass, etc.
double f_lip,q_lip,m_lip[2],k_lip_x[2],k_lip_y[2],z_lip_real,z_lip_imag;
double z_lip_real_norm,z_lip_imag_norm,z_lip_1_2_plus,z_lip_imag_prime,z_lip_2_prime;

int lip_model_flag; // YES if using my two spring model, ADACHI if using Adachi swinging lip model 

float ***site_weight;

double f_pressure_x[2],f_pressure_y[2];
double m_cell;	// mass of the air in one grid cell near the lips
double lip_left_x_sum,lip_left_y_sum,lip_right_x_sum,lip_right_y_sum;
double lip_left_y_interior_sum,lip_right_y_interior_sum,lip_width_interior_sum;
double lip_left_x_interior_sum,lip_right_x_interior_sum;

double di_center_ave[2][3],dj_center_ave[2][3];
double di_center_interior_ave[2][3],dj_center_interior_ave[2][3];

int i_bad,j_bad,k_bad,k_bad_low;	// used for diagnostics
FILE *fp_lip_left_x,*fp_lip_left_y,*fp_lip_right_x,*fp_lip_right_y;

FILE *fp_lip_left_interior_y,*fp_lip_right_interior_y,*fp_lip_width_interior;
FILE *fp_lip_left_interior_x,*fp_lip_right_interior_x;

double lip_force_x[2],lip_force_y[2];
double u_lip_upstream_ave,v_lip_upstream_ave,u_predictor_upstream_ave,v_predictor_upstream_ave;
double f_pres_upstream_ave,f_pres_downstream_ave,f_pres_y_ave;
double lip_width,lip_width_sum;
double lip_width_interior,lip_width_interior_sum;
// minimum lip opening = separation between left and right lips in grid units
// used to calculate the force that keeps them apart
double lip_opening_min;
double lip_thickness_min;
// factor used to calculation the force that keeps the lips apart and that keeps them from
// opening too wide
double k_lip_touch,lip_touch_exponent;
double j_edge_double[2],lip_opening,lip_thickness[2];
double lip_di_max;
double theta_lip_min,k_lip_angle;

double lip_angle_left;
double lip_angle_force_left;
double lip_angle_right;
double lip_angle_force_right;

int lip_touch_flag,lip_thickness_flag;

double lip_delta_x_max;
int lip_dx_max_flag;

int cell_calc_show_flag;

int
main(argc,argv)
int argc;
char *argv[];
{
	int n_threads;
	char tmp[300],mes[300];

cell_calc_show_flag = NO;

	restart_flag = START_FRESH;	/* default is a fresh start	*/
#ifdef PURDUE
	strcpy(scratch_directory,getenv("RCAC_SCRATCH"));
#endif
#ifdef AUBURN
	strcpy(scratch_directory,"/scratch/njg0003");
#endif

	if((argc <= 2) || ((argc == 3) && (strcmp(argv[1],"-h") == 0))) {			
		fprintf(stderr,"usage: %s <input_directory> <results_directory> <master_output_directory> <runxxx>\nor\n%s -restart <input_directory> <results_directory> <master_output_directory> <runxxx>\n",argv[0],argv[0]);
		exit(0);
	}
	else if((argc == 5) && (strcmp(argv[1],"-restart") == 0)) {
		strcpy(master_output_directory,argv[3]);
		strcpy(results_directory,argv[4]);
		sprintf(results_directory_full_path,"%s/%s",master_output_directory,results_directory);
		mkdir(results_directory_full_path,0777);
		sprintf(tmp,"%s/t_record_map.dat",results_directory_full_path);
		fp_t = fopen(tmp,"w");
		strcpy(input_directory,argv[2]);	/* default location for input files	*/
		sprintf(restart_maps,"%s/restart_maps.dat",scratch_directory);
		restart_flag = RE_START;
	}
	else if((argc == 4) && (strcmp(argv[1],"-restart") != 0)) {
		strcpy(master_output_directory,argv[2]);
		strcpy(results_directory,argv[3]);
		sprintf(results_directory_full_path,"%s/%s",master_output_directory,results_directory);
		mkdir(results_directory_full_path,0777);
		sprintf(tmp,"%s/t_record_map.dat",results_directory_full_path);
		fp_t = fopen(tmp,"w");
		strcpy(input_directory,argv[1]);	/* default location for input files	*/
	}
	else {
		fprintf(stderr,"unrecognized combination of arguments\n");
		fprintf(stderr,"usage: %s <input_directory> <results_directory> <master_output_directory> <runxxx>\nor\n%s -restart <input_directory> <results_directory> <master_output_directory> <runxxx>\n",argv[0],argv[0]);
		exit(0);
	}
	
/* use a log file to record important parameters and info	*/
	sprintf(tmp,"%s/log_file",results_directory_full_path);
	fp_log = fopen(tmp,"w");
	fprintf(fp_log,"using %s\n",argv[0]);
	fprintf(fp_log,"input data for grid and geometry taken from the directory %s\n",input_directory);
	fprintf(fp_log,"map data written to scratch directory %s\n",scratch_directory);
	fprintf(fp_log,"other output data written to directory %s\n",results_directory_full_path);

#ifdef CLUSTER
// take this out for icc
 	n_threads = omp_get_num_threads();	/* just to check	*/
 	fprintf(fp_log,"number of threads = %d\n",n_threads);
#endif


/* initialize the geometry of the system, including the shape and size of the recorder */
	init_geometry();

 	fprintf(fp_log,"finished init_geometry\n");

	create_arrays();

 	fprintf(fp_log,"finished create_arrays\n");

/* search through geometry file to find all boundary points on the recorder surface and	*/
/* classify them for use in dealing with boundary conditions */
	n_boundary = boundary();
	fprintf(fp_log,"number of boundary points found (on recorder) in boundary() = %d\n",n_boundary);
//	save_boundary_info();

//	display_boundary();

/* read in values for various parameters from file run_data.dat */
	init_run_data(argv[0]);

	init_lip_data();

/* initialize rho, u, and v */
	init_air();

	fflush(fp_log);

	run();

	fclose(fp_t);
	fclose(fp_log);

	cleanup_memory();

	return(0);
}

int
init_run_data(char *src_file)
{
	FILE *fp,*fp_restart;
	char tmp[300],mes[400],tmp2[300];	
	int i,j,k;

	strcpy(tmp,"run_data.dat");
	fp = fopen(tmp,"r");
	if(fp == NULL) {
		fprintf(fp_log,"can't open %s for basic run data\n",tmp);
		(void)exit(0);
	}
	
/* put a copy of run_data.dat into results directory */
	sprintf(mes,"cp %s %s/",tmp,results_directory_full_path);
	system(mes);
/* add a copy of job file too - assumed to be named job.pbs	*/
	sprintf(mes,"cp job.pbs %s/",results_directory_full_path);
	system(mes);
/* and a copy of the source code too - assumed to be named src_file	*/
	sprintf(mes,"cp %s.c %s/",src_file,results_directory_full_path);
	system(mes);

	while(1) {
		if(fgets(tmp,100,fp) == NULL) {
			fprintf(stderr, "error in reading run data file\n");
			fprintf(fp_log, "error in reading run data file\n");
			(void)exit(0);
		}
		if(tmp[0] == '#') break;
	}

	fgets(tmp,100,fp);
	sscanf(tmp,"%lf",&c_s);
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf",&rho_air);
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf",&nu);
	fgets(tmp,100,fp);
// fix a small bug here - used tmp twice  6-5-12  v8b
	sscanf(tmp,"%lf %lf %lf %lf %s",&Z_rec_1,&Z_rec_2,&Z_bound_1,&Z_bound_2,tmp2);
	if(strcmp(tmp2,"OFF") == 0) {
		boundary_Z_flag = OFF;
	}
	else {
		boundary_Z_flag = ON;
	}
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf",&courant);
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf %lf",&u_init,&t_blow_transient);
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf",&v_init);
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf %lf %lf",&t_end,&t_stop_blowing,&t_ramp_down);
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf %lf %lf %lf",&t_map_start,&t_map_end,&t_record_map,&t_map_ave);
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf",&t_record_sound);
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf",&t_restart_save_interval);
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf %lf %lf",&viscosity_1_0,&viscosity_2_0,&t_viscosity_start);
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf %lf %lf",&t_accum,&t_accum_interval,&t_accum_start);

	dt = courant * dx_min / c_s;
	if(restart_flag == START_FRESH) {
		t = t_start = 0.0;
	}	
	else {
		sprintf(tmp,"t_restart");
		fp_restart = fopen(tmp,"r");
		fscanf(fp_restart,"%lf",&t_start);
		fclose(fp_restart);
		t = t_start;
	}
	Z_rec_1_norm = Z_rec_1 / (c_s * c_s);
	Z_rec_2_norm = Z_rec_2 / (c_s * c_s);
	Z_bound_1_norm = Z_bound_1 / (c_s * c_s);
	Z_bound_2_norm = Z_bound_2 / (c_s * c_s);
	Z_rec_1_2_plus = Z_rec_1_norm + (Z_rec_2_norm/dt);
	Z_rec_2_prime = (Z_rec_2_norm/dt) / Z_rec_1_2_plus;
	Z_bound_1_2_plus = Z_bound_1_norm + (Z_bound_2_norm/dt);
	Z_bound_2_prime = (Z_bound_2_norm/dt) / Z_bound_1_2_plus;

	fprintf(fp_log,"size of simulation region: i(max) = %d\tj(max) = %d\tk(max) = %d\n",i_max,j_max,k_max);
	fprintf(fp_log,"c_s = %g\n",c_s);
	fprintf(fp_log,"rho(air) = %g\n",rho_air);
	fprintf(fp_log,"kinematic viscosity = %g\n",nu);
	fprintf(fp_log,"impedance of recorder surface = %g + i omega (%g)\n",Z_rec_1,Z_rec_2);
	fprintf(fp_log,"impedance of outer boundaries = %g + i omega (%g)\n",Z_bound_1,Z_bound_2);
	if(boundary_Z_flag == ON) {
		fprintf(fp_log,"\tuse these values for impedance of boundaries\n");
	}
	else {
		fprintf(fp_log,"\tclamp rho = u = v = 0 on boundaries\n");
	}
	fprintf(fp_log,"courant factor = %g\n",courant);
	fprintf(fp_log,"dx(min) = %g\tdt = %g\n",dx_min,dt);
	fprintf(fp_log,"u_init = %g\tv_init = %g\n",u_init,v_init);
	fprintf(fp_log,"t(ramp up channel velocity) = %g\n",t_blow_transient);
	fprintf(fp_log,"t(start) = %g\tt(end) = %g\n",t_start,t_end);
	fprintf(fp_log,"t(stop blowing) = %g\tt(ramp blowing to zero) = %g\n",t_stop_blowing,t_ramp_down);
	fprintf(fp_log,"start map recording at %g\ndt(record-maps) = %g\tdt(map ave) = %g\n",t_map_start,t_record_map,t_map_ave);
	fprintf(fp_log,"stop map recording at %g\n",t_map_end);
	fprintf(fp_log,"record rho at (%g,%g,%g), (%g,%g,%g), and (%g,%g,%g)\n",x_grid[i_record[1]],y_grid[j_record[1]],
		z_grid[k_record[1]],x_grid[i_record[2]],y_grid[j_record[2]],z_grid[k_record[2]],x_grid[i_record[3]],y_grid[j_record[3]],z_grid[k_record[3]]);
	fprintf(fp_log,"\tand at (%g,%g,%g), (%g,%g,%g), and (%g,%g,%g)\n",x_grid[i_record[4]],y_grid[j_record[4]],z_grid[i_record[4]],x_grid[j_record[5]],
		y_grid[i_record[5]],z_grid[j_record[5]],x_grid[i_record[6]],y_grid[j_record[6]],z_grid[j_record[6]]);
	fprintf(fp_log,"dt(record-sound) = %g\n",t_record_sound);
	fprintf(fp_log,"dt(record-for-restart) = %g\n",t_restart_save_interval);
	fprintf(fp_log,"artificial viscosity param1= %g and param2 =  %g\n\tturn artificial viscosity on at %g\n",viscosity_1_0,viscosity_2_0,t_viscosity_start);
	fprintf(fp_log,"average map data over time intervals of %lf s\naverage every %lf s, start averaging at %lf s\n",t_accum,t_accum_interval,t_accum_start);

	fclose(fp);

/*
	fprintf(fp_log,"\nx grid info (i, x, dx)\n");
	for(i = 0; i <= i_max; i++) fprintf(fp_log,"%d\t%g\t%g\n",i,x_grid[i],dx_grid[i]);

	fprintf(fp_log,"\ny grid info (i, y, dy)\n");
	for(j = 0; j <= j_max; j++) fprintf(fp_log,"%d\t%g\t%g\n",j,y_grid[j],dy_grid[j]);

	fprintf(fp_log,"\nz grid info (i, z, dz)\n");
	for(k = 0; k <= k_max; k++) fprintf(fp_log,"%d\t%g\t%g\n",k,z_grid[k],dz_grid[k]);
*/

	return(0);
}

/*
 *	WARNING: this routine assumes that the initialization region has
 *	v = w = 0
 *	u = constant along x and following a dependence along y that is 
 *	Poiselle-like (and read from the file u_init)
 *
 */
init_air()
{
	int i,j,k;
	FILE *fp_map_restart;
	char tmp[400],tmp2[400];
	double val_rho,val_u,val_v,val_w;

	fprintf(fp_log,"corner of initialization region at i = %d\tj = %d\tk = %d, with u(init) = %g\n",i_init_min,j_init_min,k_init_min,u_init); 

	if(restart_flag == START_FRESH) {
		fprintf(fp_log,"starting fresh\n");
		for(i = 0; i <= i_max; i++) {
			for(j = 0; j <= j_max; j++) {
				for(k = 0; k <= k_max; k++) {
					rho[i][j][k] = u[i][j][k] = v[i][j][k] = w[i][j][k] = 0.0;
					if(geometry[i][j][k] == INIT_POINT) {
						u[i][j][k] = u_predictor[i][j][k] = blowing_velocity(0.0,i,j,k);
					}
				}
			}
		}
		for(i = i_init_min; i <= i_init_max; i++) {
			for(j = j_init_min; j <= j_init_max; j++) {
				for(k = k_init_min; k <= k_init_max; k++) {
					if(geometry[i][j][k] != INIT_POINT) {
//						fprintf(fp_log,"error initializing rho in init_air()\n");
						fprintf(fp_log,"error B: initializing rho i,j,k (%d %d %d) not in init region\n",i,j,k);
						exit(0);
					}
					rho[i][j][k] = rho[i-1][j][k] + (dx_grid[i-1]*rho_air/(c_s*c_s))*nu*second_deriv_y(u,i,j,k);
				}
			}
		}
	}
	else {		/* making a restart	*/
		fprintf(fp_log,"making a restart/RESTART\n");
		sprintf(tmp2,"%s/restart_maps.dat",scratch_directory);
		fp_map_restart = fopen(tmp2,"r");
		while(1) {
			if(fgets(tmp,300,fp_map_restart) == NULL) break;
			sscanf(tmp,"%d %d %d %lf %lf %lf %lf",&i,&j,&k,&val_rho,&val_u,&val_v,&val_w);
			rho[i][j][k] = rho_predictor[i][j][k] = val_rho;
			u[i][j][k] = u_predictor[i][j][k] = val_u;
			v[i][j][k] = v_predictor[i][j][k] = val_v;
			w[i][j][k] = w_predictor[i][j][k] = val_w;
		}
		fclose(fp_map_restart);

// now get restart data for lips

//		fprintf(fp_log,"now getting restart data for lips\n");
//		fflush(fp_log);

		sprintf(tmp2,"%s/lip_restart.dat",scratch_directory);
		if((fp_map_restart = fopen(tmp2,"r")) == NULL) {
			fprintf(fp_log,"can't open lip restart map %s\n",tmp2);
			exit(0);
		}
		while(1) {
//fprintf(fp_log,"in loop to read lip restart data from %s\n",tmp2);
			if(fgets(tmp,300,fp_map_restart) == NULL) break;
//fprintf(fp_log,"getting first values in loop to read lip restart data: %s\n",tmp);
			sscanf(tmp,"%d %d",&i_lip_region_min,&i_lip_region_max);
			if(fgets(tmp,300,fp_map_restart) == NULL) break;
			sscanf(tmp,"%d %d",&j_lip_region_min,&j_lip_region_max);
			if(fgets(tmp,300,fp_map_restart) == NULL) break;
			sscanf(tmp,"%d %d",&k_lip_region_min,&k_lip_region_max);

			if(fgets(tmp,300,fp_map_restart) == NULL) break;
			sscanf(tmp,"%lf %lf",&(i_width[LEFT]),&(j_width[LEFT]));
			if(fgets(tmp,300,fp_map_restart) == NULL) break;
//			sscanf(tmp,"%lf %lf %lf %lf",&(i_center[LEFT][CURRENT]),&(i_center[LEFT][OLD]),
//				&(di_center[LEFT][CURRENT]),&(di_center[LEFT][OLD]));
			sscanf(tmp,"%lf %lf %lf %lf %lf %lf",&(i_center[LEFT][CURRENT]),&(i_center[LEFT][OLD]),
				&(di_center[LEFT][CURRENT]),&(di_center[LEFT][OLD]),
				&(di_center_interior[LEFT][CURRENT]),&(di_center_interior[LEFT][OLD]));
			if(fgets(tmp,300,fp_map_restart) == NULL) break;
			sscanf(tmp,"%lf %lf %lf %lf %lf %lf",&(j_center[LEFT][CURRENT]),&(j_center[LEFT][OLD]),
				&(dj_center[LEFT][CURRENT]),&(dj_center[LEFT][OLD]),
				&(dj_center_interior[LEFT][CURRENT]),&(dj_center_interior[LEFT][OLD]));
			if(fgets(tmp,300,fp_map_restart) == NULL) break;
			sscanf(tmp,"%d %d",&(i_corner[LEFT]),&(j_corner[LEFT]));

			if(fgets(tmp,300,fp_map_restart) == NULL) break;
			sscanf(tmp,"%lf %lf",&(i_width[RIGHT]),&(j_width[RIGHT]));
			if(fgets(tmp,300,fp_map_restart) == NULL) break;
//			sscanf(tmp,"%lf %lf %lf %lf",&(i_center[RIGHT][CURRENT]),&(i_center[RIGHT][OLD]),
//				&(di_center[RIGHT][CURRENT]),&(di_center[RIGHT][OLD]));
			sscanf(tmp,"%lf %lf %lf %lf %lf %lf",&(i_center[RIGHT][CURRENT]),&(i_center[RIGHT][OLD]),
				&(di_center[RIGHT][CURRENT]),&(di_center[RIGHT][OLD]),
				&(di_center_interior[RIGHT][CURRENT]),&(di_center_interior[RIGHT][OLD]));
			if(fgets(tmp,300,fp_map_restart) == NULL) break;
			sscanf(tmp,"%lf %lf %lf %lf %lf %lf",&(j_center[RIGHT][CURRENT]),&(j_center[RIGHT][OLD]),
				&(dj_center[RIGHT][CURRENT]),&(dj_center[RIGHT][OLD]),
				&(dj_center_interior[RIGHT][CURRENT]),&(dj_center_interior[RIGHT][OLD]));
			if(fgets(tmp,300,fp_map_restart) == NULL) break;
			sscanf(tmp,"%d %d",&(i_corner[RIGHT]),&(j_corner[RIGHT]));
//fprintf(fp_log,"done with loop to read lip restart data: %s\n",tmp);
		}
		fclose(fp_map_restart);

//		save_lip_data("just readin lip data from restart file");

//		fprintf(fp_log,"finish getting lip data from lip_restart.dat\n");
//		fflush(fp_log);
		update_lip_geometry_v2(VERBOSE);
//		save_lip_data("lip data after return from update lip");
//		fprintf(fp_log,"finish updating geometry for restart\n");
//		fflush(fp_log);
		calc_site_weights();
//		save_lip_data("lip data after return from calc site weights");
//		fprintf(fp_log,"finish calculating new site weights\n");
//		fflush(fp_log);
	}

	reset_map(rho_buf);	/* zero these buffers prior to start	*/
	reset_map(u_buf);
	reset_map(v_buf);
	reset_map(w_buf);

	
//	fprintf(fp_log,"ready to start run()\n");

	save_lip_data("lip data for restart");

	return(0);
}

save_lip_data(char *s)
{
	fprintf(fp_log,"%s\n",s);

	fprintf(fp_log,"lip region min/max for i,j,k\n");
	fprintf(fp_log,"%d\t%d\n%d\t%d\n%d\t%d\n",i_lip_region_min,i_lip_region_max,
		j_lip_region_min,j_lip_region_max,k_lip_region_min,k_lip_region_max);
	fprintf(fp_log,"left lip width for i,j\n");
	fprintf(fp_log,"%g\t%g\n",i_width[LEFT],j_width[LEFT]);
	fprintf(fp_log,"left lip i current/old,j current/old\n");
//	fprintf(fp_log,"%g\t%g\t%g\t%g\n",i_center[LEFT][CURRENT],i_center[LEFT][OLD],
//		di_center[LEFT][CURRENT],di_center[LEFT][OLD]);
	fprintf(fp_log,"%g\t%g\t%g\t%g\t%g\t%g\n",i_center[LEFT][CURRENT],i_center[LEFT][OLD],
		di_center[LEFT][CURRENT],di_center[LEFT][OLD],
		di_center_interior[LEFT][CURRENT],di_center_interior[LEFT][OLD]);
	fprintf(fp_log,"left lip di current/old,dj current/old\tdj_interior\n");
	fprintf(fp_log,"%g\t%g\t%g\t%g\t%g\t%g\n",j_center[LEFT][CURRENT],j_center[LEFT][OLD],
		dj_center[LEFT][CURRENT],dj_center[LEFT][OLD],
		dj_center_interior[LEFT][CURRENT],dj_center_interior[LEFT][OLD]);
	fprintf(fp_log,"left lip corner i/j\n");
	fprintf(fp_log,"%d\t%d\n",i_corner[LEFT],j_corner[LEFT]);

	fprintf(fp_log,"right lip width for i,j\n");
	fprintf(fp_log,"%g\t%g\n",i_width[RIGHT],j_width[RIGHT]);
	fprintf(fp_log,"right lip i current/old,j current/old\n");
//	fprintf(fp_log,"%g\t%g\t%g\t%g\n",i_center[RIGHT][CURRENT],i_center[RIGHT][OLD],
//		di_center[RIGHT][CURRENT],di_center[RIGHT][OLD]);
	fprintf(fp_log,"%g\t%g\t%g\t%g\t%g\t%g\n",i_center[RIGHT][CURRENT],i_center[RIGHT][OLD],
		di_center[RIGHT][CURRENT],di_center[RIGHT][OLD],
		di_center_interior[RIGHT][CURRENT],di_center_interior[RIGHT][OLD]);
	fprintf(fp_log,"right lip di current/old,dj current/old\tdj_interior\n");
	fprintf(fp_log,"%g\t%g\t%g\t%g\n",j_center[RIGHT][CURRENT],j_center[RIGHT][OLD],
		dj_center[RIGHT][CURRENT],dj_center[RIGHT][OLD],
		dj_center_interior[RIGHT][CURRENT],dj_center_interior[RIGHT][OLD]);
	fprintf(fp_log,"right lip corner i/j\n");
	fprintf(fp_log,"%d\t%d\n",i_corner[RIGHT],j_corner[RIGHT]);

	return(0);
}

int
init_geometry()
{
	int i,j,k,n,m,p;
	FILE *fp_solid,*fp_sound,*fp_initialize,*fp_x_grid,*fp_y_grid,*fp_z_grid,*fp_u_init;
	FILE *fp_surface_normal,*fp_lip;
	char tmp[300],tmp2[300];
	int i_rec,j_rec,k_rec;
	char mes[400];
	double x_tmp,y,z;
	double di_start,dj_start;

        int i_left_min,i_left_max,j_left_min,j_left_max,k_left_min,k_left_max;
        int i_right_min,i_right_max,j_right_min,j_right_max,k_right_min,k_right_max;

	dx_min = 1.0;
	sprintf(tmp,"%s/x_grid.dat",input_directory);
	fp_x_grid = fopen(tmp,"r");
	if(fp_x_grid == NULL) {
		fprintf(fp_log,"can't open %s for x grid data\n",tmp);
		exit(0);
	}
	sprintf(mes,"cp %s %s/",tmp,results_directory_full_path);
	system(mes);
		/* put a copy of this file into the results directory */
	i = 0;
	while(1) {
		if(fgets(tmp,200,fp_x_grid) == NULL) break;
		sscanf(tmp,"%d %lf %lf",&n,&(x_grid[i]),&(dx_grid[i]));
		if(dx_min > dx_grid[i]) dx_min = dx_grid[i];
		++i;
	}
	i_max = i - 1;
	fclose(fp_x_grid);

	sprintf(tmp,"%s/y_grid.dat",input_directory);
	fp_y_grid = fopen(tmp,"r");
	if(fp_y_grid == NULL) {
		fprintf(fp_log,"can't open %s for y grid data\n",tmp);
		exit(0);
	}
	sprintf(mes,"cp %s %s/",tmp,results_directory_full_path);
	system(mes);
		/* put a copy of this file into the results directory */
	j = 0;
	while(1) {
		if(fgets(tmp,200,fp_y_grid) == NULL) break;
		sscanf(tmp,"%d %lf %lf",&n,&(y_grid[j]),&(dy_grid[j]));
		if(dx_min > dy_grid[j]) dx_min = dy_grid[j];
		++j;
	}
	j_max = j - 1;
	fclose(fp_y_grid);

// now ready for the grid data along z
	sprintf(tmp,"%s/z_grid.dat",input_directory);
	fp_z_grid = fopen(tmp,"r");
	if(fp_z_grid == NULL) {
		fprintf(fp_log,"can't open %s for z grid data\n",tmp);
		exit(0);
	}
	sprintf(mes,"cp %s %s/",tmp,results_directory_full_path);
	system(mes);
		/* put a copy of this file into the results directory */
	k = 0;
	while(1) {
		if(fgets(tmp,200,fp_z_grid) == NULL) break;
		sscanf(tmp,"%d %lf %lf",&n,&(z_grid[k]),&(dz_grid[k]));
		if(dx_min > dz_grid[k]) dx_min = dz_grid[k];
		++k;
	}
	k_max = k - 1;
	fclose(fp_z_grid);

// allocate memory for geometry array - this is its first use
	geometry = allocate_array_of_integers(i_max+2,j_max+2,k_max+2);

	for(i = 0; i <= i_max; i++) {
		for(j = 0; j <= j_max; j++) {
			for(k = 0; k <= k_max; k++) {
				geometry[i][j][k] = OPEN;
			}
		}
	}

	sprintf(tmp,"%s/geometry_solid.dat",input_directory);
	fp_solid = fopen(tmp,"r");
	if(fp_solid == NULL) {
		fprintf(fp_log,"can't open %s for geometry data\n",tmp);
		exit(0);
	}
	sprintf(mes,"cp %s %s/",tmp,results_directory_full_path);
	system(mes);
		/* put a copy of this file into the results directory */

	fprintf(fp_log,"coordinate ranges (x) %d, (y) %d, (z) %d \n",i_max,j_max,k_max);

	while(1) {
		if(fgets(tmp,200,fp_solid) == NULL) break;
		sscanf(tmp,"%d %d %d",&i,&j,&k);
		if((i > i_max) || (j > j_max) || (k > k_max)) {
			fprintf(fp_log,"coordinates %d,%d,%d in geometry_solid.dat out of bounds\n",i,j,k);
			fflush(fp_log);
			exit(0);
		}
		geometry[i][j][k] = SOLID;
	}
	fclose(fp_solid);

	sprintf(tmp,"%s/geometry_left_lip.dat",input_directory);
	fp_lip = fopen(tmp,"r");
	if(fp_lip == NULL) {
		fprintf(fp_log,"can't open %s for lip data\n",tmp);
		exit(0);
	}
	sprintf(mes,"cp %s %s/",tmp,results_directory_full_path);
	system(mes);
		/* put a copy of this file into the results directory */

// first mark out lip region for undisplaced lips

	while(1) {
		if(fgets(tmp,200,fp_lip) == NULL) break;
		sscanf(tmp,"%d %d %d",&i,&j,&k);
		if((i > i_max) || (j > j_max) || (k > k_max)) {
			fprintf(fp_log,"coordinates %d,%d,%d in geometry_solid.dat out of bounds\n",i,j,k);
			fflush(fp_log);
			exit(0);
		}
		geometry[i][j][k] = LEFT_LIP;
	}
	fclose(fp_lip);

	sprintf(tmp,"%s/geometry_right_lip.dat",input_directory);
	fp_lip = fopen(tmp,"r");
	if(fp_lip == NULL) {
		fprintf(fp_log,"can't open %s for lip data\n",tmp);
		exit(0);
	}
	sprintf(mes,"cp %s %s/",tmp,results_directory_full_path);
	system(mes);
		/* put a copy of this file into the results directory */

	while(1) {
		if(fgets(tmp,200,fp_lip) == NULL) break;
		sscanf(tmp,"%d %d %d",&i,&j,&k);
		if((i > i_max) || (j > j_max) || (k > k_max)) {
			fprintf(fp_log,"coordinates %d,%d,%d in geometry_solid.dat out of bounds\n",i,j,k);
			fflush(fp_log);
			exit(0);
		}
		geometry[i][j][k] = RIGHT_LIP;
	}
	fclose(fp_lip);

//	next extract needed lip info

        i_left_min = i_max;
        i_left_max = 0;
        j_left_min = j_max;
        j_left_max = 0;
        k_left_min = k_max;
        k_left_max = 0;

        i_right_min = i_max;
        i_right_max = 0;
        j_right_min = j_max;
        j_right_max = 0;
        k_right_min = k_max;
        k_right_max = 0;

        for(i = 0; i <= i_max; i++) {
                for(j = 0; j <= j_max; j++) {
                        for(k = 0; k <= k_max; k++) {
                                if(geometry[i][j][k] == LEFT_LIP) {
                                        if(i < i_left_min) i_left_min = i;
                                        if(i > i_left_max) i_left_max = i;
                                        if(j < j_left_min) j_left_min = j;
                                        if(j > j_left_max) j_left_max = j;
                                        if(k < k_left_min) k_left_min = k;
                                        if(k > k_left_max) k_left_max = k;
                                }
                                if(geometry[i][j][k] == RIGHT_LIP) {
                                        if(i < i_right_min) i_right_min = i;
                                        if(i > i_right_max) i_right_max = i;
                                        if(j < j_right_min) j_right_min = j;
                                        if(j > j_right_max) j_right_max = j;
                                        if(k < k_right_min) k_right_min = k;
                                        if(k > k_right_max) k_right_max = k;
                                }
                        }
                }
        }

	fprintf(fp_log,"lip boundaries: left: %d/%d\t%d/%d\t%d/%d\n",
		i_left_min,i_left_max,j_left_min,j_left_max,k_left_min,k_left_max);
	fprintf(fp_log,"lip boundaries: right: %d/%d\t%d/%d\t%d/%d\n",
		i_right_min,i_right_max,j_right_min,j_right_max,k_right_min,k_right_max);

        i_corner[LEFT] = i_left_min;
        j_corner[LEFT] = j_left_min;
        k_corner[LEFT] = k_left_min;
        i_corner[RIGHT] = i_right_min;
        j_corner[RIGHT] = j_right_max;
        k_corner[RIGHT] = k_right_min;

        i_pivot[LEFT] = i_left_min;
        j_pivot[LEFT] = j_left_min - 1;

        i_pivot[RIGHT] = i_right_min;
        j_pivot[RIGHT] = j_right_max + 1;

        i_origin[LEFT] = ((double)(i_left_max + i_left_min)) / 2;
        j_origin[LEFT] = ((double)(j_left_max + j_left_min)) / 2;

        i_origin[RIGHT] = ((double)(i_right_max + i_right_min)) / 2;
        j_origin[RIGHT] = ((double)(j_right_max + j_right_min)) / 2;

        i_width[LEFT] = i_left_max - i_origin[LEFT];
        j_width[LEFT] = j_left_max - j_origin[LEFT];

        i_width[RIGHT] = i_right_max - i_origin[RIGHT];
        j_width[RIGHT] = j_right_max - j_origin[RIGHT];

// give the lips some initial displacement to make sure they oscillate properly
di_start = 1.0;
dj_start = 0.6;

di_start = -1.6;
dj_start = -1.4;

di_start = -0.2;
dj_start = -0.2;

di_start = 1.0;
dj_start = -0.7;

// di_start = 0.3;
// dj_start = 0.0;

di_start = 0.0;
dj_start = 0.0;

        di_center[LEFT][CURRENT] = di_center[LEFT][NEW] = di_center[LEFT][OLD] = di_start;	// 0.0;
        dj_center[LEFT][CURRENT] = dj_center[LEFT][NEW] = dj_center[LEFT][OLD] = dj_start;	// 0.0;
        i_center[LEFT][CURRENT] = i_center[LEFT][NEW] = i_center[LEFT][OLD] = i_origin[LEFT] + di_center[LEFT][CURRENT];
        j_center[LEFT][CURRENT] = j_center[LEFT][NEW] = j_center[LEFT][OLD] = j_origin[LEFT] + dj_center[LEFT][CURRENT];

        di_center_interior[LEFT][CURRENT] = di_center_interior[LEFT][NEW] = di_center_interior[LEFT][OLD] = dj_start;	// 0.0;
        dj_center_interior[LEFT][CURRENT] = dj_center_interior[LEFT][NEW] = dj_center_interior[LEFT][OLD] = dj_start;	// 0.0;

        di_center[RIGHT][CURRENT] = di_center[RIGHT][NEW] = di_center[RIGHT][OLD] = di_start;	// 0.0;
        dj_center[RIGHT][CURRENT] = dj_center[RIGHT][NEW] = dj_center[RIGHT][OLD] = -dj_start;	// 0.0;
        i_center[RIGHT][CURRENT] = i_center[RIGHT][NEW] = i_center[RIGHT][OLD] = i_origin[RIGHT] + di_center[RIGHT][CURRENT];
        j_center[RIGHT][CURRENT] = j_center[RIGHT][NEW] = j_center[RIGHT][OLD] = j_origin[RIGHT] + dj_center[RIGHT][CURRENT];

        di_center_interior[RIGHT][CURRENT] = di_center_interior[RIGHT][NEW] = di_center_interior[RIGHT][OLD] = -dj_start;	// 0.0;
        dj_center_interior[RIGHT][CURRENT] = dj_center_interior[RIGHT][NEW] = dj_center_interior[RIGHT][OLD] = -dj_start;	// 0.0;

	fprintf(fp_log,"lip info: left: %d/%d\t%g/%g\t%g/%g\n",
		i_pivot[LEFT],j_pivot[LEFT],i_origin[LEFT],j_origin[LEFT],i_width[LEFT],j_width[LEFT]);
	fprintf(fp_log,"lip info: right: %d/%d\t%g/%g\t%g/%g\n",
		i_pivot[RIGHT],j_pivot[RIGHT],i_origin[RIGHT],j_origin[RIGHT],i_width[RIGHT],j_width[RIGHT]);

	i_lip_region_max = i_corner[LEFT] + 2 * i_width[LEFT] + 5 * j_width[LEFT];
	i_lip_region_min = i_corner[LEFT] - 3 * j_width[LEFT]; 
	j_lip_region_max = j_pivot[RIGHT];
	j_lip_region_min = j_pivot[LEFT];
	k_lip_region_max = k_left_max;
	k_lip_region_min = k_left_min;

	display_lip_region("display (1) undisplaced lip sites from geom files without ghost cells\n");

	clear_lip_region();

	display_lip_region("display (1.1) clear geom array in lip region\n");

	update_lip_geometry_v2(VERBOSE);

	display_lip_region("display (1.5) lip sites with initial displacement without ghost cells\n");

	find_ghost_sites(NOT_STARTED);	// find and mark ghost sites

	fprintf(fp_log,"coordinate ranges (x) %d, (y) %d, (z) %d \n",i_max,j_max,k_max);

	display_lip_region("display (2) lip sites from geom files WITH ghost cells\n");

// 	next deal with init region where u is imposed
	i_init_min = i_max;
	i_init_max = 0;
	j_init_min = j_max;
	j_init_max = 0;
	k_init_min = k_max;
	k_init_max = 0;
	sprintf(tmp,"%s/geometry_initialize.dat",input_directory);
	fp_initialize = fopen(tmp,"r");
	if(fp_initialize == NULL) {
		fprintf(fp_log,"can't open %s for geometry data\n",tmp);
		exit(0);
	}
	sprintf(mes,"cp %s %s/",tmp,results_directory_full_path);
	system(mes);
		/* put a copy of this file into the results directory */
	while(1) {
		if(fgets(tmp,200,fp_initialize) == NULL) break;
		sscanf(tmp,"%d %d %d",&i,&j,&k);
		if((i > i_max) || (j > j_max) || (k > k_max)) {
			fprintf(fp_log,"coordinates %d,%d,%d in geometry_initialize.dat out of bounds\n",i,j,k);
			fflush(fp_log);
			exit(0);
		}
		geometry[i][j][k] = INIT_POINT;
		if(i < i_init_min) i_init_min = i;
		if(i > i_init_max) i_init_max = i;
		if(j < j_init_min) j_init_min = j;
		if(j > j_init_max) j_init_max = j;
		if(k < k_init_min) k_init_min = k;
		if(k > k_init_max) k_init_max = k;
	}
	fclose(fp_initialize);

	fprintf(fp_log,"coordinate ranges for initialization of u:\n(x) %d-%d, (y) %d-%d, (z) %d-%d \n",i_init_min,i_init_max,j_init_min,j_init_max,k_init_min,k_init_max);

	sprintf(tmp,"%s/geometry_sound.dat",input_directory);
	fp_sound = fopen(tmp,"r");
	if(fp_sound == NULL) {
		fprintf(fp_log,"can't open %s for geometry sound data\n",tmp);
		fflush(fp_log);
		exit(0);
	}
	sprintf(mes,"cp %s %s/",tmp,results_directory_full_path);
	system(mes); 	/* put a copy of this file into the results directory */

	n = 1;
	while(1) {
		if(fgets(tmp,200,fp_sound) == NULL) break;
		if(n > 20) {
			fprintf(fp_log,"something is wrong in %s\n",tmp);
			fflush(fp_log);
			exit(0);
		}
		sscanf(tmp,"%d %d %d",&i,&j,&k);
		if((i > i_max) || (j > j_max) || (k > k_max)) {
			fprintf(fp_log,"coordinates %d,%d,%d in geometry_sound.dat out of bounds\n",i,j,k);
			fflush(fp_log);
			exit(0);
		}
		i_record[n] = i;
		j_record[n] = j;
		k_record[n] = k;
		fprintf(fp_log,"recording point %d for rho and u is i = %d\tj = %d\tk = %d\n",n,i,j,k);
		n_record_sound = n;
		++n;
	}
	fclose(fp_sound);

	for(i = 0; i <= i_max; i++) {
		for(k = 0; k <= k_max; k++) {
			geometry[i][0][k] = LOWER_Y_BOUNDARY;
			geometry[i][j_max][k] = UPPER_Y_BOUNDARY;
		}
	}
	for(j = 0; j <= j_max; j++) {
		for(k = 0; k <= k_max; k++) {
			geometry[0][j][k] = LOWER_X_BOUNDARY;
			geometry[i_max][j][k] = UPPER_X_BOUNDARY;
		}
	}
	for(i = 0; i <= i_max; i++) {
		for(j = 0; j <= j_max; j++) {
			geometry[i][j][0] = LOWER_Z_BOUNDARY;
			geometry[i][j][k_max] = UPPER_Z_BOUNDARY;
		}
	}

	sprintf(tmp,"%s/u_init.dat",input_directory);
	fp_u_init = fopen(tmp,"r");
	if(fp_u_init == NULL) {
		fprintf(fp_log,"can't open %s for u initialization data\n",tmp);
		fflush(fp_log);
		exit(0);
	}
	sprintf(mes,"cp %s %s/",tmp,results_directory_full_path);
	system(mes); 		/* put a copy of this file into the results directory */
	for(j = j_init_min; j <= j_init_max; j++) {
		fscanf(fp_u_init,"%lf",&(init_val_j[j]));
	}
	for(k = k_init_min; k <= k_init_max; k++) {
// make these all = 1.0 for now		fscanf(fp_u_init,"%lf",&(init_val_k[k]));
		init_val_k[k] = 1.0;
	}
	fclose(fp_u_init);

	fprintf(fp_log,"init factors for u(init) in channel\n");
	fprintf(fp_log,"along y direction:\n"); 
	for(j = j_init_min; j <= j_init_max; j++) {
		fprintf(fp_log,"\t%lf",init_val_j[j]);
	}
	fprintf(fp_log,"\n");
	fprintf(fp_log,"along z direction:\n");
	for(k = k_init_min; k <= k_init_max; k++) {
		fprintf(fp_log,"\t%lf",init_val_k[k]);
	}
	fprintf(fp_log,"\n");

// now check for and readin surface normal data
	sprintf(tmp,"%s/surface_point_info.dat",input_directory);
	fp_surface_normal = fopen(tmp,"r");
	if(fp_surface_normal == NULL) {
		surface_normal_flag = NO;
		fprintf(fp_log,"\nNOT using surface normal info\n\n");
	}
	else {
		surface_normal_flag = YES;
		n_surface_points = 0;
		fprintf(fp_log,"\nusing surface normal info from file %s\n\n",tmp);

/* add a copy of surface normal file too - assumed to be named surface_point_info.dat	*/
		sprintf(mes,"cp %s/surface_point_info.dat %s/",input_directory,results_directory_full_path);
		system(mes);

		while(1) {
			if((fscanf(fp_surface_normal,"%d %d %d %lf %lf %lf",&i,&j,&k,&x_tmp,&y,&z)) == EOF) break;
			i_surface[n_surface_points] = i;
			j_surface[n_surface_points] = j;
			k_surface[n_surface_points] = k;
			x_hat[n_surface_points] = x_tmp;
			y_hat[n_surface_points] = y;
			z_hat[n_surface_points] = z;
			boundary_flag[n_surface_points] = CORNER;
			if(x_hat[n_surface_points] > 0.9) boundary_flag[n_surface_points] = XUP;
			if(x_hat[n_surface_points] < -0.9) boundary_flag[n_surface_points] = XDOWN;
			if(y_hat[n_surface_points] > 0.9) boundary_flag[n_surface_points] = YUP;
			if(y_hat[n_surface_points] < -0.9) boundary_flag[n_surface_points] = YDOWN;
			if(z_hat[n_surface_points] > 0.9) boundary_flag[n_surface_points] = ZUP;
			if(z_hat[n_surface_points] < -0.9) boundary_flag[n_surface_points] = ZDOWN;

			++n_surface_points;
		}
		fprintf(fp_log,"\nnumber of surface normal points from surface_normal file %d\n\n",n_surface_points);
		fclose(fp_surface_normal);
	}
	
	return(0);
}

/*
 *	display the geometry of the simulation
 *	the points where the velocity is initialize (and held fixed) are in red
 *	the two points where rho-vs-time is recordeded are blue
 *
 *	put this plot in the file results_directory_full_path/geometry.pdf
 */
/* don't bother with this routine for now - or perhaps anymore!
display_geometry(n)
int n;
{
	int i,j;
	FILE *fp1,*fp2,*fp3;
	char mes[400],tmp[300];

	fp1 = fopen("geometry1.dat","w");
	fp2 = fopen("geometry2.dat","w");
	fp3 = fopen("geometry3.dat","w");

	for(i = 0; i <= i_max; i++) {
		for(j = 0; j <= j_max; j++) {
			if(geometry[i][j] == INIT_POINT) {
				fprintf(fp2,"%g\t%g\n",x_grid[i],y_grid[j]);
			}
			else if(geometry[i][j] !=  OPEN) {
				fprintf(fp1,"%g\t%g\n",x_grid[i],y_grid[j]);
			}
			fprintf(fp3,"%g\t%g\n",x_grid[i_record[1]],y_grid[j_record[1]]);
			fprintf(fp3,"%g\t%g\n",x_grid[i_record[2]],y_grid[j_record[2]]);
			fprintf(fp3,"%g\t%g\n",x_grid[i_record[3]],y_grid[j_record[3]]);
		}
	}

	fflush(fp1);
	fflush(fp2);
	fflush(fp3);
	fclose(fp1);
	fclose(fp2);
	fclose(fp3);

#ifdef CLUSTER
	sprintf(mes,"graph -r -.2 -u .1 -w .8 -h .8 -P -E -g 1 -m 0 -f geometry1.dat -o -f geometry2.dat -H 1 -m 0 -o -f geometry3.dat -m 0 -H 2 | plot2ps > %s/geometry.%d.eps",results_directory_full_path,n);
	system(mes);
#endif

#ifdef LAPTOP 
	sprintf(mes,"graph -r -.2 -u .1 -w .8 -h .8 -P -E -g 1 -m 0 -f geometry1.dat -o -f geometry2.dat -H 1 -m 0 -o -f geometry3.dat -m 0 -H 2 | plot2ps > %s/geometry.%d.eps",results_directory_full_path,n);
	system(mes);
 	sprintf(mes,"pstopdf %s/geometry.%d.eps -o %s/geometry_%d.pdf",results_directory_full_path,n,results_directory_full_path,n); 
	system(mes); 
#endif

	return;
}
*/

/*
 *	do the calculation here
 *	use explicit MacCormack method
 *
 *	results for rho vs time at three locations are also stored
 *	along with map data for rho, u, v, and w if desired
 */
run()
{
	int i,j,k,k_map,k2,m,n_record,n_record_2,n_file_num,p;
	FILE *fp_rho_t[21];
	FILE *fp_vel_t[21];
	FILE *fp_lip_width;
	FILE *fp_lip_force_y[2],*fp_lip_force_x[2];
	FILE *fp_rho_mid_lip;
	FILE *fp_rho_lip_upstream_edge,*fp_rho_lip_downstream_edge;
	FILE *fp_vel_mid_lip,*fp_vel_entrance_lip,*fp_vel_exit_lip;
	FILE *fp_rho_entrance_lip,*fp_rho_exit_lip;
	char tmp1[300],tmp2[300],tmp3[300],tmp4[300];
	double t_next_map;	/*	time at which to save next set of maps	*/
	double t_next_record;	/*	time to record next map			*/
	double t_next_restart_save;
	double viscosity_1,viscosity_2;
	int n_threads;
	double current_t,start_t;
	int n_benchmark;
	double t_next_accum,t_accum_end;
	int n_accum_buffer_count;
	int accum_flag;
	int nan_flag = NO;
	double rho_max,x_max,y_max,z_max;
	double vel_perp;
	int i_big,j_big,k_big; // for diagnostics
	double rho_mid_lip_sum,rho_exit_lip_sum,rho_lip_upstream_edge_sum,rho_lip_downstream_edge_sum;
	double rho_entrance_lip_sum,vel_mid_lip_sum;
	double vel_entrance_lip_sum,vel_exit_lip_sum;
	int k_mid;

	for(i = 1; i <= n_record_sound; i++) {
		sprintf(tmp1,"%s/rho_time_%d",results_directory_full_path,i);
		fp_rho_t[i] = fopen(tmp1,"w");
		sprintf(tmp1,"%s/v_x_time_%d",results_directory_full_path,i);
		fp_vel_t[i] = fopen(tmp1,"w");
	}

	sprintf(tmp1,"%s/lip_left_x",results_directory_full_path);
	fp_lip_left_x = fopen(tmp1,"w");
	sprintf(tmp1,"%s/lip_left_y",results_directory_full_path);
	fp_lip_left_y = fopen(tmp1,"w");
	sprintf(tmp1,"%s/lip_right_x",results_directory_full_path);
	fp_lip_right_x = fopen(tmp1,"w");
	sprintf(tmp1,"%s/lip_right_y",results_directory_full_path);
	fp_lip_right_y = fopen(tmp1,"w");
	sprintf(tmp1,"%s/lip_width",results_directory_full_path);
	fp_lip_width = fopen(tmp1,"w");

	sprintf(tmp1,"%s/lip_left_interior_y",results_directory_full_path);
	fp_lip_left_interior_y = fopen(tmp1,"w");
	sprintf(tmp1,"%s/lip_right_interior_y",results_directory_full_path);
	fp_lip_right_interior_y = fopen(tmp1,"w");
	sprintf(tmp1,"%s/lip_width_interior",results_directory_full_path);
	fp_lip_width_interior = fopen(tmp1,"w");

	sprintf(tmp1,"%s/lip_left_interior_x",results_directory_full_path);
	fp_lip_left_interior_x = fopen(tmp1,"w");
	sprintf(tmp1,"%s/lip_right_interior_x",results_directory_full_path);
	fp_lip_right_interior_x = fopen(tmp1,"w");

	sprintf(tmp1,"%s/lip_force_y_left",results_directory_full_path);
	fp_lip_force_y[LEFT] = fopen(tmp1,"w");
	sprintf(tmp1,"%s/lip_force_y_right",results_directory_full_path);
	fp_lip_force_y[RIGHT] = fopen(tmp1,"w");
	sprintf(tmp1,"%s/lip_force_x_left",results_directory_full_path);
	fp_lip_force_x[LEFT] = fopen(tmp1,"w");
	sprintf(tmp1,"%s/lip_force_x_right",results_directory_full_path);
	fp_lip_force_x[RIGHT] = fopen(tmp1,"w");

	sprintf(tmp1,"%s/rho_mid_lip",results_directory_full_path);
	fp_rho_mid_lip = fopen(tmp1,"w");
	sprintf(tmp1,"%s/vel_mid_lip",results_directory_full_path);
	fp_vel_mid_lip = fopen(tmp1,"w");
	sprintf(tmp1,"%s/rho_entrance_lip",results_directory_full_path);
	fp_rho_entrance_lip = fopen(tmp1,"w");
	sprintf(tmp1,"%s/rho_exit_lip",results_directory_full_path);
	fp_rho_exit_lip = fopen(tmp1,"w");
	sprintf(tmp1,"%s/vel_entrance_lip",results_directory_full_path);
	fp_vel_entrance_lip = fopen(tmp1,"w");
	sprintf(tmp1,"%s/vel_exit_lip",results_directory_full_path);
	fp_vel_exit_lip = fopen(tmp1,"w");
	sprintf(tmp1,"%s/rho_lip_upstream_edge",results_directory_full_path);
	fp_rho_lip_upstream_edge = fopen(tmp1,"w");
	sprintf(tmp1,"%s/rho_lip_downstream_edge",results_directory_full_path);
	fp_rho_lip_downstream_edge = fopen(tmp1,"w");

	n_record_2 = t_record_sound / dt;
	t_next_record = t_map_start;
	t_next_map = t_next_record - t_map_ave;

	n_record = t_record_map / (2 *  dt);
	n_record_2 = t_record_sound / (2 *  dt);
	t_next_restart_save = t + t_restart_save_interval;

	if(restart_flag == RE_START) {
		if(t >= t_accum_start) {
			t_next_accum = t + t_accum_interval;
		}
		else {
			t_next_accum = t_accum_start;
		}
	}	
	else {
		t_next_accum = t_accum_start;
	}
	t_accum_end = t_next_accum + t_accum;

	zero_filtering_data();
	n_accum_buffer_count = 0;
	accum_flag = NO;

	n_file_num = 1;
	k_map = 0;
	k2 = 0;
	for(i = 1; i <= n_record_sound; i++) {
		rho_t_sum[i] = 0.0;
		vel_t_sum[i] = 0.0;
	}

	lip_left_x_sum = lip_left_y_sum = lip_right_x_sum = lip_right_y_sum = lip_width_sum = 0.0;
	lip_left_y_interior_sum = lip_right_y_interior_sum = lip_width_interior_sum = 0.0;
	lip_left_x_interior_sum = lip_right_x_interior_sum = 0.0;
	t_sum = 0.0;
	lip_force_y_sum[LEFT] = lip_force_y_sum[RIGHT] = lip_force_x_sum[LEFT] = lip_force_x_sum[RIGHT] = 0.0;
	rho_mid_lip_sum = vel_mid_lip_sum = vel_entrance_lip_sum = vel_exit_lip_sum = 0.0;
	rho_lip_upstream_edge_sum = rho_lip_downstream_edge_sum = rho_entrance_lip_sum = rho_exit_lip_sum = 0.0;
	k_mid = (k_lip_region_min + k_lip_region_max) / 2;

	viscosity_1 = viscosity_2 = 0.0;
	if(t >= t_viscosity_start) {
		viscosity_1 = viscosity_1_0;
		viscosity_2 = viscosity_2_0;
	}

	if(restart_flag != RE_START) {
		for(i = 1; i <= n_record_sound; i++) {
			fprintf(fp_rho_t[i],"%g\t%g\n",t_sum,rho[i_record[i]][j_record[i]][k_record[i]]);
			fflush(fp_rho_t[i]);
		}	

		fprintf(fp_lip_left_x,"%g\t%g\n",t_sum,di_center[LEFT][CURRENT]);
		fprintf(fp_lip_left_y,"%g\t%g\n",t_sum,dj_center[LEFT][CURRENT]);
		fprintf(fp_lip_right_x,"%g\t%g\n",t_sum,di_center[RIGHT][CURRENT]);
		fprintf(fp_lip_right_y,"%g\t%g\n",t_sum,dj_center[RIGHT][CURRENT]);

		lip_width = j_center[RIGHT][CURRENT] - j_width[RIGHT] + dj_center[RIGHT][CURRENT] 
        	- (j_center[LEFT][CURRENT] + j_width[LEFT] + dj_center[LEFT][CURRENT]);
		fprintf(fp_lip_width,"%g\t%g\n",t_sum,lip_width);

		fprintf(fp_lip_left_interior_y,"%g\t%g\n",t_sum,dj_center_interior[LEFT][CURRENT]);
		fprintf(fp_lip_right_interior_y,"%g\t%g\n",t_sum,dj_center_interior[RIGHT][CURRENT]);

		fprintf(fp_lip_left_interior_x,"%g\t%g\n",t_sum,di_center_interior[LEFT][CURRENT]);
		fprintf(fp_lip_right_interior_x,"%g\t%g\n",t_sum,di_center_interior[RIGHT][CURRENT]);

		lip_width_interior = j_center[RIGHT][CURRENT] - j_width[RIGHT] 
			+ (dj_center_interior[RIGHT][CURRENT]-dj_center[RIGHT][CURRENT]) + dj_center_interior[RIGHT][CURRENT]
        	- (j_center[LEFT][CURRENT] + j_width[LEFT] 
			+ (dj_center_interior[LEFT][CURRENT]-dj_center[LEFT][CURRENT]) + dj_center_interior[LEFT][CURRENT]);
		fprintf(fp_lip_width_interior,"%g\t%g\n",t_sum,lip_width_interior);

		fflush(fp_lip_left_x);
		fflush(fp_lip_left_y);
		fflush(fp_lip_right_x);
		fflush(fp_lip_right_y);
		fflush(fp_lip_width);
	}
	n_threads = 0;

#ifdef CLUSTER
#pragma omp parallel 
{
// take out for icc
 n_threads = omp_get_num_threads();	/* just to check	*/
 if(omp_get_thread_num() == 1) {
 	fprintf(fp_log,"number of threads = %d\n",n_threads);
 	fflush(fp_log);
 }
}
#endif

#ifdef BENCHMARK
n_benchmark = 0;
start_t = current_t = omp_get_wtime();
fprintf(fp_log,"real start to calc\tt = %g\n",current_t);
#endif

//	ghost sites have already been found and marked - now just update the site weights
//	need to be sure that they are marked on restarts

	display_lip_region("display (2.5) starting lip map\n");
fflush(fp_log);
update_lip_geometry_v2(VERBOSE);
fflush(fp_log);
	display_lip_region("display (3) starting lip map\n");
fflush(fp_log);
fprintf(fp_log,"just before starting run and after displacing lips\n");
fflush(fp_log);
	calc_site_weights();
fflush(fp_log);

	display_lip_region("display (4) starting lip map\n");
fflush(fp_log);
	display_cell_values("starting site values");
fflush(fp_log);

// if(cell_calc_show_flag == YES) exit(0);

	fprintf(fp_log,"starting run()\n");
fflush(fp_log);

  while(t <= t_end) {
{

#ifdef BENCHMARK
start_t = current_t = omp_get_wtime();
fprintf(fp_log,"start first mac loop\tt = %g\n",current_t);
#endif

//fprintf(fp_log,"start first mac loop\tt = %g\n",t);
//fprintf(fp_log,"in mac (0.2)\tt = %g\n",t);
//fflush(fp_log);


// nan_check(1,&i_bad,&j_bad,&k_bad);

#ifdef CLUSTER
#pragma omp collapse(3)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif

	for(i = 1; i <= i_max-1; i++) {
		for(j = 1; j <= j_max-1; j++) {
			for(k = 1; k <= k_max-1; k++) {
/* for interior points, away from any boundaries			 */
/* do predictor step */
				if((geometry[i][j][k] == OPEN)||(geometry[i][j][k] == GHOST)) {
			  	rho_predictor[i][j][k] = rho[i][j][k]
				  - (dt/dx_grid[i]) * u[i][j][k] * (rho[i+1][j][k] - rho[i][j][k])
				  - (dt/dx_grid[i]) * rho_air * (u[i+1][j][k] - u[i][j][k])
				  - (dt/dy_grid[j]) * v[i][j][k] * (rho[i][j+1][k] - rho[i][j][k])
				  - (dt/dy_grid[j]) * rho_air * (v[i][j+1][k] - v[i][j][k])
				  - (dt/dz_grid[k]) * w[i][j][k] * (rho[i][j][k+1] - rho[i][j][k])
				  - (dt/dz_grid[k]) * rho_air * (w[i][j][k+1] - w[i][j][k])
				  + artificial_viscosity(i,j,k,rho,rho,viscosity_1,viscosity_2);

				  u_predictor[i][j][k] = u[i][j][k] 
				  - (dt/dx_grid[i]) * u[i][j][k] * (u[i+1][j][k] - u[i][j][k])
				  - (dt/dy_grid[j]) * v[i][j][k] * (u[i][j+1][k] - u[i][j][k])
				  - (dt/dz_grid[k]) * w[i][j][k] * (u[i][j][k+1] - u[i][j][k])
				  -(c_s*c_s/rho_air)*(dt/dx_grid[i]) * (rho[i+1][j][k] - rho[i][j][k])
				  +nu*dt*(second_deriv_x(u,i,j,k)+second_deriv_y(u,i,j,k)+second_deriv_z(u,i,j,k))
				  + artificial_viscosity(i,j,k,u,rho,viscosity_1,viscosity_2);

				  v_predictor[i][j][k] = v[i][j][k] 
				  - (dt/dx_grid[i]) * u[i][j][k] * (v[i+1][j][k] - v[i][j][k])
				  - (dt/dy_grid[j]) * v[i][j][k] * (v[i][j+1][k] - v[i][j][k])
				  - (dt/dz_grid[k]) * w[i][j][k] * (v[i][j][k+1] - v[i][j][k])
				  -(c_s*c_s/rho_air)*(dt/dy_grid[j]) * (rho[i][j+1][k] - rho[i][j][k])
				  +nu*dt*(second_deriv_x(v,i,j,k)+second_deriv_y(v,i,j,k)+second_deriv_z(v,i,j,k))
				  + artificial_viscosity(i,j,k,v,rho,viscosity_1,viscosity_2);

				  w_predictor[i][j][k] = w[i][j][k] 
				  - (dt/dx_grid[i]) * u[i][j][k] * (w[i+1][j][k] - w[i][j][k])
				  - (dt/dy_grid[j]) * v[i][j][k] * (w[i][j+1][k] - w[i][j][k])
				  - (dt/dz_grid[k]) * w[i][j][k] * (w[i][j][k+1] - w[i][j][k])
				  -(c_s*c_s/rho_air)*(dt/dz_grid[k]) * (rho[i][j][k+1] - rho[i][j][k])
				  +nu*dt*(second_deriv_x(w,i,j,k)+second_deriv_y(w,i,j,k)+second_deriv_z(w,i,j,k))
// fixed this error 6-6-12 v8b	  + artificial_viscosity(i,j,k,v,viscosity_1,viscosity_2);
				  + artificial_viscosity(i,j,k,w,rho,viscosity_1,viscosity_2);
				}
			}
		}
	}
}

#ifdef BENCHMARK
current_t = omp_get_wtime();
fprintf(fp_log,"finished first mac loop (1)\tt = %g\n",current_t - start_t);
#endif

//fprintf(fp_log,"in mac (1)\tt = %g\n",t);
//fflush(fp_log);

{

if(surface_normal_flag == NO) {

#ifdef CLUSTER
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor) private(i,j,k,m)
#endif

/* next deal with points on the surface of the recorder - these have an acoustic impedance Z */
	for(m = 0; m < n_boundary; m++) {
		i = x_boundary[m];
		j = y_boundary[m];
		k = z_boundary[m];
	   if(check_neighborhood(i,j,k) == COVERED_BY_LIP) { // code added 09-13-16
		rho_predictor[i][j][k] = 0.0;
		u_predictor[i][j][k] = 0.0;
		v_predictor[i][j][k] = 0.0;
		w_predictor[i][j][k] = 0.0;
	   }
	   else {
		if(boundary_flag[m] == XUP) {
			v_predictor[i][j][k] = w_predictor[i][j][k] = 0.0;
			rho_predictor[i][j][k] = rho[i][j][k]
						-(dt/dx_grid[i])*rho_air*(u[i+1][j][k] - u[i][j][k])
						-(dt/dx_grid[i])*u[i][j][k]*(rho[i+1][j][k] - rho[i][j][k])
                                + artificial_viscosity_on_recorder(m,i,j,k,viscosity_1,viscosity_2);
			u_predictor[i][j][k] = u[i][j][k] * Z_rec_2_prime + rho_predictor[i][j][k] / Z_rec_1_2_plus;
		}
		if(boundary_flag[m] == XDOWN) {
			v_predictor[i][j][k] = w_predictor[i][j][k] = 0.0;
			rho_predictor[i][j][k] = rho[i][j][k]
						-(dt/dx_grid[i-1])*rho_air*(u[i][j][k] - u[i-1][j][k])
						-(dt/dx_grid[i-1])*u[i][j][k]*(rho[i][j][k] - rho[i-1][j][k])
                                + artificial_viscosity_on_recorder(m,i,j,k,viscosity_1,viscosity_2);
			u_predictor[i][j][k] = u[i][j][k] * Z_rec_2_prime + rho_predictor[i][j][k] / Z_rec_1_2_plus;
		}
		if(boundary_flag[m] == YUP) {
			u_predictor[i][j][k] = w_predictor[i][j][k] = 0.0;
			rho_predictor[i][j][k] = rho[i][j][k]
						-(dt/dy_grid[j])*rho_air*(v[i][j+1][k] - v[i][j][k])
						-(dt/dy_grid[j])*v[i][j][k]*(rho[i][j+1][k] - rho[i][j][k])
                                + artificial_viscosity_on_recorder(m,i,j,k,viscosity_1,viscosity_2);
			v_predictor[i][j][k] = v[i][j][k] * Z_rec_2_prime + rho_predictor[i][j][k] / Z_rec_1_2_plus;
		}
		if(boundary_flag[m] == YDOWN) {
			u_predictor[i][j][k] = w_predictor[i][j][k] = 0.0;
			rho_predictor[i][j][k] = rho[i][j][k]
						-(dt/dy_grid[j-1])*rho_air*(v[i][j][k] - v[i][j-1][k])
						-(dt/dy_grid[j-1])*v[i][j][k]*(rho[i][j][k] - rho[i][j-1][k])
                                + artificial_viscosity_on_recorder(m,i,j,k,viscosity_1,viscosity_2);
			v_predictor[i][j][k] = v[i][j][k] * Z_rec_2_prime + rho_predictor[i][j][k] / Z_rec_1_2_plus;
		}
		if(boundary_flag[m] == ZUP) {
			u_predictor[i][j][k] = v_predictor[i][j][k] = 0.0;
			rho_predictor[i][j][k] = rho[i][j][k]
						-(dt/dz_grid[k])*rho_air*(w[i][j][k+1] - w[i][j][k])
						-(dt/dz_grid[k])*w[i][j][k]*(rho[i][j][k+1] - rho[i][j][k])
                                + artificial_viscosity_on_recorder(m,i,j,k,viscosity_1,viscosity_2);
			w_predictor[i][j][k] = w[i][j][k] * Z_rec_2_prime + rho_predictor[i][j][k] / Z_rec_1_2_plus;
		}
		if(boundary_flag[m] == ZDOWN) {
			u_predictor[i][j][k] = v_predictor[i][j][k] = 0.0;
			rho_predictor[i][j][k] = rho[i][j][k]
						-(dt/dz_grid[k-1])*rho_air*(w[i][j][k] - w[i][j][k-1])
						-(dt/dz_grid[k-1])*w[i][j][k]*(rho[i][j][k] - rho[i][j][k-1])
                                + artificial_viscosity_on_recorder(m,i,j,k,viscosity_1,viscosity_2);
			w_predictor[i][j][k] = w[i][j][k] * Z_rec_2_prime + rho_predictor[i][j][k] / Z_rec_1_2_plus;
		}
	   }
	}
}
else {


/* next deal with points on the surface of the recorder using the surface normal info 
							- these have an acoustic impedance Z */
#ifdef CLUSTER
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor) private(i,j,k,m)
#endif

	for(m = 0; m < n_surface_points; m++) {
		i = i_surface[m];
		j = j_surface[m];
		k = k_surface[m];
	   if(check_neighborhood(i,j,k) == COVERED_BY_LIP) {
		rho_predictor[i][j][k] = 0.0;
		u_predictor[i][j][k] = 0.0;
		v_predictor[i][j][k] = 0.0;
		w_predictor[i][j][k] = 0.0;
	   }
	   else {
		rho_predictor[i][j][k] = rho[i][j][k] + artificial_viscosity_on_recorder(m,i,j,k,viscosity_1,viscosity_2);

		if(x_hat[m] > 0.1) {
			rho_predictor[i][j][k] += 
				-(dt/dx_grid[i])*rho_air*(u[i+1][j][k] - u[i][j][k])
				-(dt/dx_grid[i])*u[i][j][k]*(rho[i+1][j][k] - rho[i][j][k]);
		}
		else if(x_hat[m] < -0.1) {
			rho_predictor[i][j][k] += 
				-(dt/dx_grid[i-1])*rho_air*(u[i][j][k] - u[i-1][j][k])
				-(dt/dx_grid[i-1])*u[i][j][k]*(rho[i][j][k] - rho[i-1][j][k]);
		}
		if(y_hat[m] > 0.1) {
			rho_predictor[i][j][k] += 
				-(dt/dy_grid[j])*rho_air*(v[i][j+1][k] - v[i][j][k])
				-(dt/dy_grid[j])*v[i][j][k]*(rho[i][j+1][k] - rho[i][j][k]);
		}
		else if(y_hat[m] < -0.1) {
			rho_predictor[i][j][k] += 
				-(dt/dy_grid[j-1])*rho_air*(v[i][j][k] - v[i][j-1][k])
				-(dt/dy_grid[j-1])*v[i][j][k]*(rho[i][j][k] - rho[i][j-1][k]);
		}
		if(z_hat[m] > 0.1) {
			rho_predictor[i][j][k] += 
				-(dt/dz_grid[k])*rho_air*(w[i][j][k+1] - w[i][j][k])
				-(dt/dz_grid[k])*w[i][j][k]*(rho[i][j][k+1] - rho[i][j][k]);
		}
		else if(z_hat[m] < -0.1) {
			rho_predictor[i][j][k] += 
				-(dt/dz_grid[k-1])*rho_air*(w[i][j][k] - w[i][j][k-1])
				-(dt/dz_grid[k-1])*w[i][j][k]*(rho[i][j][k] - rho[i][j][k-1]);
		}

// not sure if this will fix the problem with using surface_normal_info with moving lip but
// it should make this code act more like above without surface_normal_info
		if((fabs(x_hat[m]) < 0.1) && (fabs(y_hat[m]) < 0.1)) {	// this surface is in x-y plane 
			u_predictor[i][j][k] = v_predictor[i][j][k] = 0.0;
		}
			
		if((fabs(y_hat[m]) < 0.1) && (fabs(z_hat[m]) < 0.1)) {	// this surface is in y-z plane 
			v_predictor[i][j][k] = w_predictor[i][j][k] = 0.0;
		}

		if((fabs(z_hat[m]) < 0.1) && (fabs(x_hat[m]) < 0.1)) {	// this surface is in z-x plane 
			w_predictor[i][j][k] = u_predictor[i][j][k] = 0.0;
		}

		vel_perp = rho_predictor[i][j][k] / Z_rec_1_2_plus;
		u_predictor[i][j][k] = u[i][j][k] * Z_rec_2_prime + vel_perp * x_hat[m]; 
		v_predictor[i][j][k] = v[i][j][k] * Z_rec_2_prime + vel_perp * y_hat[m]; 
		w_predictor[i][j][k] = w[i][j][k] * Z_rec_2_prime + vel_perp * z_hat[m]; 

	   }
	}

}

/* next deal with points on the boundaries - 
	these have an acoustic impedance Z_bound = Z_bound_1 + i omega Z_bound_2 
   note that we don't have to worry about the corners
*/
	if(boundary_Z_flag == ON) {

#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
		for(j = 1; j <= j_max - 1; j++) {	// boundary plane at x = 0 
			for(k = 1; k <= k_max - 1; k++) {	
				v_predictor[0][j][k] = w_predictor[0][j][k] = 0.0;
				rho_predictor[0][j][k] = rho[0][j][k] 
							-(dt/dx_grid[0])*rho_air*(u[1][j][k] - u[0][j][k])
							-(dt/dx_grid[0])*u[0][j][k]*(rho[1][j][k] - rho[0][j][k])
               	                 + artificial_viscosity_on_boundary(0,j,k,viscosity_1,viscosity_2);
				u_predictor[0][j][k] 
				= u[0][j][k]*Z_bound_2_prime+rho_predictor[0][j][k]/Z_bound_1_2_plus;
			}
		}
#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
		for(j = 1; j <= j_max - 1; j++) {	// boundary plane at x = x_max
			for(k = 1; k <= k_max - 1; k++) {	
				v_predictor[i_max][j][k] = w_predictor[i_max][j][k] = 0.0;
				rho_predictor[i_max][j][k] = rho[i_max][j][k]
					-(dt/dx_grid[i_max-1])*rho_air*(u[i_max][j][k]-u[i_max-1][j][k])
					-(dt/dx_grid[i_max-1])*u[i_max][j][k]*(rho[i_max][j][k]-rho[i_max-1][j][k])
               	                 + artificial_viscosity_on_boundary(i_max,j,k,viscosity_1,viscosity_2);
				u_predictor[i_max][j][k] 
				= u[i_max][j][k]*Z_bound_2_prime+rho_predictor[i_max][j][k]/Z_bound_1_2_plus;
			}
		}
#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
		for(i = 1; i <= i_max - 1; i++) {	// boundary plane at y = 0
			for(k = 1; k <= k_max - 1; k++) {	
				u_predictor[i][0][k] = w_predictor[i][0][k] = 0.0;
				rho_predictor[i][0][k] = rho[i][0][k]
							-(dt/dy_grid[0])*rho_air*(v[i][1][k] - v[i][0][k])
							-(dt/dy_grid[0])*v[i][0][k]*(rho[i][1][k] - rho[i][0][k])
               	                 + artificial_viscosity_on_boundary(i,0,k,viscosity_1,viscosity_2);
				v_predictor[i][0][k] = 
				v[i][0][k] * Z_bound_2_prime + rho_predictor[i][0][k] / Z_bound_1_2_plus;
			}
		}
#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
		for(i = 1; i <= i_max - 1; i++) {	// boundary plane at y = y_max
			for(k = 1; k <= k_max - 1; k++) {	
				u_predictor[i][j_max][k] = w_predictor[i][j_max][k] = 0.0;
				rho_predictor[i][j_max][k] = rho[i][j_max][k]
					-(dt/dy_grid[j_max-1])*rho_air*(v[i][j_max][k] - v[i][j_max-1][k])
					-(dt/dy_grid[j_max-1])*v[i][j_max][k]*(rho[i][j_max][k]-rho[i][j_max-1][k])
               	                 + artificial_viscosity_on_boundary(i,j_max,k,viscosity_1,viscosity_2);
				v_predictor[i][j_max][k] = 
				v[i][j_max][k] * Z_bound_2_prime + rho_predictor[i][j_max][k] / Z_bound_1_2_plus;
			}
		}
#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
		for(i = 1; i <= i_max - 1; i++) {	// boundary plane at z = 0
			for(j = 1; j <= j_max - 1; j++) {	
				u_predictor[i][j][0] = v_predictor[i][j][0] = 0.0;
				rho_predictor[i][j][0] = rho[i][j][0]
							-(dt/dz_grid[0])*rho_air*(w[i][j][1] - w[i][j][0])
							-(dt/dz_grid[0])*w[i][j][0]*(rho[i][j][1] - rho[i][j][0])
               	                 + artificial_viscosity_on_boundary(i,j,0,viscosity_1,viscosity_2);
				w_predictor[i][j][0] = 
				w[i][j][0] * Z_bound_2_prime + rho_predictor[i][j][0] / Z_bound_1_2_plus;
			}
		}
#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
		for(i = 1; i <= i_max - 1; i++) {	// boundary plane at z = z_max
			for(j = 1; j <= j_max - 1; j++) {	
				u_predictor[i][j][k_max] = v_predictor[i][j][k_max] = 0.0;
				rho_predictor[i][j][k_max] = rho[i][j][k_max]
					-(dt/dz_grid[k_max-1])*rho_air*(w[i][j][k_max] - w[i][j][k_max-1])
					-(dt/dz_grid[k_max-1])*w[i][j][k_max]*(rho[i][j][k_max]-rho[i][j][k_max-1])
               	                 + artificial_viscosity_on_boundary(i,j,k_max,viscosity_1,viscosity_2);
				w_predictor[i][j][k_max] = 
				w[i][j][k_max] * Z_bound_2_prime + rho_predictor[i][j][k_max] / Z_bound_1_2_plus;
			}
		}
	}
}


/* now deal with rho in region where u is held constant	*/
	for(i = i_init_min; i <= i_init_max; i++) {
		for(j = j_init_min; j <= j_init_max; j++) {
			for(k = k_init_min; k <= k_init_max; k++) {
				rho_predictor[i][j][k] = rho_predictor[i-1][j][k] + (dx_grid[i-1]*rho_air/(c_s*c_s))*nu*second_deriv_y(u_predictor,i,j,k);
			}
		}
	}

// now deal with ghost sites on lip edges
//	update_velocity_on_lip_surfaces();

//fprintf(fp_log,"in mac (2)\tt = %g\n",t);
//fflush(fp_log);

#ifdef BENCHMARK
current_t = omp_get_wtime();
fprintf(fp_log,"starting second mac loop (2)\tt = %g\n",current_t - start_t);
#endif

{

#ifdef CLUSTER
#pragma omp collapse(3)
#pragma omp parallel for shared(rho,u,v,w,u_predictor,v_predictor,w_predictor,rho_predictor) private(i,j,k)
#endif

	for(i = 1; i <= i_max-1; i++) {
		for(j = 1; j <= j_max-1; j++) {
			for(k = 1; k <= k_max-1; k++) {
/* for interior points, away from any boundaries			 */
/* next do corrector step */
				if((geometry[i][j][k] == OPEN)||(geometry[i][j][k] == GHOST)) {

			  rho[i][j][k] = 0.5 * (rho[i][j][k] + rho_predictor[i][j][k] 
-(dt/dx_grid[i-1]) * rho_air * (u_predictor[i][j][k] - u_predictor[i-1][j][k])  
-(dt/dx_grid[i-1]) * u_predictor[i][j][k] * (rho_predictor[i][j][k] - rho_predictor[i-1][j][k])
-(dt/dy_grid[j-1]) * rho_air * (v_predictor[i][j][k] - v_predictor[i][j-1][k])
-(dt/dy_grid[j-1]) * v_predictor[i][j][k] * (rho_predictor[i][j][k] - rho_predictor[i][j-1][k])
-(dt/dz_grid[k-1]) * rho_air * (w_predictor[i][j][k] - w_predictor[i][j][k-1])
-(dt/dz_grid[k-1]) * w_predictor[i][j][k] * (rho_predictor[i][j][k] - rho_predictor[i][j][k-1])
			  + artificial_viscosity(i,j,k,rho_predictor,rho_predictor,viscosity_1,viscosity_2));

			  u[i][j][k] = 0.5 * (u[i][j][k] + u_predictor[i][j][k]
-(dt/dx_grid[i-1]) * u_predictor[i][j][k] * (u_predictor[i][j][k] - u_predictor[i-1][j][k]) 
-(dt/dy_grid[j-1]) * v_predictor[i][j][k] * (u_predictor[i][j][k] - u_predictor[i][j-1][k]) 
-(dt/dz_grid[k-1]) * w_predictor[i][j][k] * (u_predictor[i][j][k] - u_predictor[i][j][k-1]) 
-(c_s*c_s/rho_air)*(dt/dx_grid[i-1]) * (rho_predictor[i][j][k] - rho_predictor[i-1][j][k])
+nu*dt*(second_deriv_x(u_predictor,i,j,k) + second_deriv_y(u_predictor,i,j,k)+second_deriv_z(u_predictor,i,j,k))
			  + artificial_viscosity(i,j,k,u_predictor,rho_predictor,viscosity_1,viscosity_2));
	
			  v[i][j][k] = 0.5 * (v[i][j][k] + v_predictor[i][j][k]
-(dt/dx_grid[i-1]) * u_predictor[i][j][k] * (v_predictor[i][j][k] - v_predictor[i-1][j][k]) 
-(dt/dy_grid[j-1]) * v_predictor[i][j][k] * (v_predictor[i][j][k] - v_predictor[i][j-1][k]) 
-(dt/dz_grid[k-1]) * w_predictor[i][j][k] * (v_predictor[i][j][k] - v_predictor[i][j][k-1]) 
-(c_s*c_s/rho_air)*(dt/dy_grid[j-1]) * (rho_predictor[i][j][k] - rho_predictor[i][j-1][k])
+nu*dt*(second_deriv_x(v_predictor,i,j,k) + second_deriv_y(v_predictor,i,j,k)+second_deriv_z(v_predictor,i,j,k))
			  + artificial_viscosity(i,j,k,v_predictor,rho_predictor,viscosity_1,viscosity_2));
	
			  w[i][j][k] = 0.5 * (w[i][j][k] + w_predictor[i][j][k]
-(dt/dx_grid[i-1]) * u_predictor[i][j][k] * (w_predictor[i][j][k] - w_predictor[i-1][j][k]) 
-(dt/dy_grid[j-1]) * v_predictor[i][j][k] * (w_predictor[i][j][k] - w_predictor[i][j-1][k]) 
-(dt/dz_grid[k-1]) * w_predictor[i][j][k] * (w_predictor[i][j][k] - w_predictor[i][j][k-1]) 
-(c_s*c_s/rho_air)*(dt/dz_grid[k-1]) * (rho_predictor[i][j][k] - rho_predictor[i][j][k-1])
+nu*dt*(second_deriv_x(w_predictor,i,j,k) + second_deriv_y(w_predictor,i,j,k)+second_deriv_z(w_predictor,i,j,k))
			  + artificial_viscosity(i,j,k,w_predictor,rho_predictor,viscosity_1,viscosity_2));
				}
			}
		}
	}
}

//fprintf(fp_log,"in mac (2.1)\tt = %g\n",t);
//fflush(fp_log);

#ifdef BENCHMARK
current_t = omp_get_wtime();
fprintf(fp_log,"finished second mac loop (3)\tt = %g\n",current_t - start_t);
#endif

{

/* finally - update points on recorder */
#ifdef CLUSTER
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor) private(i,j,k,m)
#endif

        for(m = 0; m < n_boundary; m++) {
                i = x_boundary[m];
                j = y_boundary[m];
                k = z_boundary[m];
                u[i][j][k] = u_predictor[i][j][k];
                v[i][j][k] = v_predictor[i][j][k];
                w[i][j][k] = w_predictor[i][j][k];
                rho[i][j][k] = rho_predictor[i][j][k];
        }

//fprintf(fp_log,"in mac (2.2)\tt = %g\n",t);
//fflush(fp_log);

/* update points on the boundaries - note that we don't have to worry about the corners
*/

        if(boundary_Z_flag == ON) {

#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
                for(j = 1; j <= j_max - 1; j++) {       // x = 0 plane
                	for(k = 1; k <= k_max - 1; k++) { 
                                rho[0][j][k] = rho_predictor[0][j][k];
                                u[0][j][k] = u_predictor[0][j][k];
                                v[0][j][k] = v_predictor[0][j][k];
                                w[0][j][k] = w_predictor[0][j][k];
			}
                }
#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
                for(j = 1; j <= j_max - 1; j++) {       // x = x_max plane
                	for(k = 1; k <= k_max - 1; k++) { 
                                rho[i_max][j][k] = rho_predictor[i_max][j][k];
                                u[i_max][j][k] = u_predictor[i_max][j][k];
                                v[i_max][j][k] = v_predictor[i_max][j][k];
                                w[i_max][j][k] = w_predictor[i_max][j][k];
			}
                }
#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
                for(i = 1; i <= i_max - 1; i++) {       // y = 0 plane
                	for(k = 1; k <= k_max - 1; k++) { 
                                rho[i][0][k] = rho_predictor[i][0][k];
                                v[i][0][k] = v_predictor[i][0][k];
                                u[i][0][k] = u_predictor[i][0][k];
                                w[i][0][k] = w_predictor[i][0][k];
			}
                }
#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
                for(i = 1; i <= i_max - 1; i++) {       // y = y_max plane
                	for(k = 1; k <= k_max - 1; k++) { 
                                rho[i][j_max][k] = rho_predictor[i][j_max][k];
                                v[i][j_max][k] = v_predictor[i][j_max][k];
                                u[i][j_max][k] = u_predictor[i][j_max][k];
                                w[i][j_max][k] = w_predictor[i][j_max][k];
			}
                }
#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
                for(i = 1; i <= i_max - 1; i++) {       // z = 0 plane
                	for(j = j; j <= j_max - 1; j++) { 
                                rho[i][j][0] = rho_predictor[i][j][0];
                                w[i][j][0] = w_predictor[i][j][0];
                                u[i][j][0] = u_predictor[i][j][0];
                                v[i][j][0] = v_predictor[i][j][0];
			}
                }
#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
                for(i = 1; i <= i_max - 1; i++) {       // z = z_max plane
                	for(j = 1; j <= j_max - 1; j++) { 
                                rho[i][j][k_max] = rho_predictor[i][j][k_max];
                                w[i][j][k_max] = w_predictor[i][j][k_max];
                                u[i][j][k_max] = u_predictor[i][j][k_max];
                                v[i][j][k_max] = v_predictor[i][j][k_max];
			}
                }
        }
}

//fprintf(fp_log,"in mac (2.3)\tt = %g\n",t);
//fflush(fp_log);

/* now deal with rho in region where u is held constant	*/
	for(i = i_init_min; i <= i_init_max; i++) {
		for(j = j_init_min; j <= j_init_max; j++) {
			for(k = k_init_min; k <= k_init_max; k++) {
				rho[i][j][k] = rho[i-1][j][k] + (dx_grid[i-1]*rho_air/(c_s*c_s))*nu*second_deriv_y(u,i,j,k);
			}
		}
	}

//fprintf(fp_log,"in mac (2.4)\tt = %g\n",t);
//fflush(fp_log);

	if(accum_flag == YES) {
		accum_filtering_data();
		++n_accum_buffer_count;
	}
// now test for nan and record problem locations in log_file - if any are found then exit
/*
 */
#ifdef CLUSTER
#pragma omp collapse(3)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
        for(i = 1; i <= i_max-1; i++) {
                for(j = 1; j <= j_max-1; j++) {
                        for(k = 1; k <= k_max-1; k++) {
                                if(fabs(rho[i][j][k]) > 1e3) {
                                        fprintf(fp_log,"(a) rho too large %g\t%d\t%d\t%d\n",rho[i][j][k],i,j,k);
                                        nan_flag = YES;
                                }
                        }
                }
        }

//fprintf(fp_log,"in mac (3)\tt = %g\n",t);
//fflush(fp_log);

	update_velocity_on_lip_surfaces2();

//fprintf(fp_log,"in mac (4)\tt = %g\n",t);
//fflush(fp_log);

	save_lip_predictors();

//fprintf(fp_log,"in mac (5)\tt = %g\n",t);
//fflush(fp_log);

	move_lips();

//fprintf(fp_log,"in mac (6)\tt = %g\n",t);
//fflush(fp_log);

	update_lip_geometry_v2(QUIET);

//fprintf(fp_log,"in mac (7)\tt = %g\n",t);
//fflush(fp_log);

	calc_site_weights();

/* now do MacCormack again but this time lead with backward derivatives */
{

#ifdef BENCHMARK
current_t = omp_get_wtime();
fprintf(fp_log,"starting third mac loop (4)\tt = %g\n",current_t - start_t);
#endif
// fprintf(fp_log,"starting third mac loop (4)\tt = %g\n",current_t - start_t);
// fflush(fp_log);

#ifdef CLUSTER
#pragma omp collapse(3)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor) private(i,j,k)
#endif

	for(i = 1; i <= i_max-1; i++) {
		for(j = 1; j <= j_max-1; j++) {
			for(k = 1; k <= k_max-1; k++) {
/* for interior points, away from any boundaries			 */
//				if(geometry[i][j][k] == OPEN) {
				if((geometry[i][j][k] == OPEN)||(geometry[i][j][k] == GHOST)) {
//				if((geometry[i][j][k] == OPEN)||(geometry[i][j][k] == LEFT_LIP)||(geometry[i][j][k] == RIGHT_LIP)) {
				  rho_predictor[i][j][k] = rho[i][j][k]
				  - (dt/dx_grid[i-1]) * u[i][j][k] * (rho[i][j][k] - rho[i-1][j][k])
				  - (dt/dx_grid[i-1]) * rho_air * (u[i][j][k] - u[i-1][j][k])
				  - (dt/dy_grid[j-1]) * v[i][j][k] * (rho[i][j][k] - rho[i][j-1][k])
				  - (dt/dy_grid[j-1]) * rho_air * (v[i][j][k] - v[i][j-1][k])
				  - (dt/dz_grid[k-1]) * w[i][j][k] * (rho[i][j][k] - rho[i][j][k-1])
				  - (dt/dz_grid[k-1]) * rho_air * (w[i][j][k] - w[i][j][k-1])
				  + artificial_viscosity(i,j,k,rho,rho,viscosity_1,viscosity_2);

				  u_predictor[i][j][k] = u[i][j][k] 
				  - (dt/dx_grid[i-1]) * u[i][j][k] * (u[i][j][k] - u[i-1][j][k])
				  - (dt/dy_grid[j-1]) * v[i][j][k] * (u[i][j][k] - u[i][j-1][k])
				  - (dt/dz_grid[k-1]) * w[i][j][k] * (u[i][j][k] - u[i][j][k-1])
				  -(c_s*c_s/rho_air)*(dt/dx_grid[i-1]) * (rho[i][j][k] - rho[i-1][j][k])
				  +nu*dt*(second_deriv_x(u,i,j,k)+second_deriv_y(u,i,j,k)+second_deriv_z(u,i,j,k))
				  + artificial_viscosity(i,j,k,u,rho,viscosity_1,viscosity_2);

				  v_predictor[i][j][k] = v[i][j][k] 
				  - (dt/dx_grid[i-1]) * u[i][j][k] * (v[i][j][k] - v[i-1][j][k])
				  - (dt/dy_grid[j-1]) * v[i][j][k] * (v[i][j][k] - v[i][j-1][k])
				  - (dt/dz_grid[k-1]) * w[i][j][k] * (v[i][j][k] - v[i][j][k-1])
				  -(c_s*c_s/rho_air)*(dt/dy_grid[j-1]) * (rho[i][j][k] - rho[i][j-1][k])
				  +nu*dt*(second_deriv_x(v,i,j,k)+second_deriv_y(v,i,j,k)+second_deriv_z(v,i,j,k))
				  + artificial_viscosity(i,j,k,v,rho,viscosity_1,viscosity_2);

				  w_predictor[i][j][k] = w[i][j][k] 
				  - (dt/dx_grid[i-1]) * u[i][j][k] * (w[i][j][k] - w[i-1][j][k])
				  - (dt/dy_grid[j-1]) * v[i][j][k] * (w[i][j][k] - w[i][j-1][k])
				  - (dt/dz_grid[k-1]) * w[i][j][k] * (w[i][j][k] - w[i][j][k-1])
				  -(c_s*c_s/rho_air)*(dt/dz_grid[k-1]) * (rho[i][j][k] - rho[i][j][k-1])
				  +nu*dt*(second_deriv_x(w,i,j,k)+second_deriv_y(w,i,j,k)+second_deriv_z(w,i,j,k))
				  + artificial_viscosity(i,j,k,w,rho,viscosity_1,viscosity_2);
				}
			}
		}
	}
}

#ifdef BENCHMARK
current_t = omp_get_wtime();
fprintf(fp_log,"finished third mac loop (5)\tt = %g\n",current_t - start_t);
#endif

{

/* next deal with points on the surface of the recorder - these have an acoustic impedance Z_rec_1 + i omega Z_rec_2 */

if(surface_normal_flag == NO) {

#ifdef CLUSTER
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor) private(i,j,k,m)
#endif

	for(m = 0; m < n_boundary; m++) {
		i = x_boundary[m];
		j = y_boundary[m];
		k = z_boundary[m];
	   if(check_neighborhood(i,j,k) == COVERED_BY_LIP) { // code added 09-13-16
		rho_predictor[i][j][k] = 0.0;
		u_predictor[i][j][k] = 0.0;
		v_predictor[i][j][k] = 0.0;
		w_predictor[i][j][k] = 0.0;
	   }
	   else {
		if(boundary_flag[m] == XUP) {
			v_predictor[i][j][k] = w_predictor[i][j][k] = 0.0;
			rho_predictor[i][j][k] = rho[i][j][k]
						-(dt/dx_grid[i])*rho_air*(u[i+1][j][k] - u[i][j][k])
						-(dt/dx_grid[i])*u[i][j][k]*(rho[i+1][j][k] - rho[i][j][k])
                                + artificial_viscosity_on_recorder(m,i,j,k,viscosity_1,viscosity_2);
			u_predictor[i][j][k] = u[i][j][k] * Z_rec_2_prime + rho_predictor[i][j][k] / Z_rec_1_2_plus;
		}
		if(boundary_flag[m] == XDOWN) {
			v_predictor[i][j][k] = w_predictor[i][j][k] = 0.0;
			rho_predictor[i][j][k] = rho[i][j][k]
						-(dt/dx_grid[i-1])*rho_air*(u[i][j][k] - u[i-1][j][k])
						-(dt/dx_grid[i-1])*u[i][j][k]*(rho[i][j][k] - rho[i-1][j][k])
                                + artificial_viscosity_on_recorder(m,i,j,k,viscosity_1,viscosity_2);
			u_predictor[i][j][k] = u[i][j][k] * Z_rec_2_prime + rho_predictor[i][j][k] / Z_rec_1_2_plus;
		}
		if(boundary_flag[m] == YUP) {
			u_predictor[i][j][k] = w_predictor[i][j][k] = 0.0;
			rho_predictor[i][j][k] = rho[i][j][k]
						-(dt/dy_grid[j])*rho_air*(v[i][j+1][k] - v[i][j][k])
						-(dt/dy_grid[j])*v[i][j][k]*(rho[i][j+1][k] - rho[i][j][k])
                                + artificial_viscosity_on_recorder(m,i,j,k,viscosity_1,viscosity_2);
			v_predictor[i][j][k] = v[i][j][k] * Z_rec_2_prime + rho_predictor[i][j][k] / Z_rec_1_2_plus;
		}
		if(boundary_flag[m] == YDOWN) {
			u_predictor[i][j][k] = w_predictor[i][j][k] = 0.0;
			rho_predictor[i][j][k] = rho[i][j][k]
						-(dt/dy_grid[j-1])*rho_air*(v[i][j][k] - v[i][j-1][k])
						-(dt/dy_grid[j-1])*v[i][j][k]*(rho[i][j][k] - rho[i][j-1][k])
                                + artificial_viscosity_on_recorder(m,i,j,k,viscosity_1,viscosity_2);
			v_predictor[i][j][k] = v[i][j][k] * Z_rec_2_prime + rho_predictor[i][j][k] / Z_rec_1_2_plus;
		}
		if(boundary_flag[m] == ZUP) {
			u_predictor[i][j][k] = v_predictor[i][j][k] = 0.0;
			rho_predictor[i][j][k] = rho[i][j][k]
						-(dt/dz_grid[k])*rho_air*(w[i][j][k+1] - w[i][j][k])
						-(dt/dz_grid[k])*w[i][j][k]*(rho[i][j][k+1] - rho[i][j][k])
                                + artificial_viscosity_on_recorder(m,i,j,k,viscosity_1,viscosity_2);
			w_predictor[i][j][k] = w[i][j][k] * Z_rec_2_prime + rho_predictor[i][j][k] / Z_rec_1_2_plus;
		}
		if(boundary_flag[m] == ZDOWN) {
			u_predictor[i][j][k] = v_predictor[i][j][k] = 0.0;
			rho_predictor[i][j][k] = rho[i][j][k]
						-(dt/dz_grid[k-1])*rho_air*(w[i][j][k] - w[i][j][k-1])
						-(dt/dz_grid[k-1])*w[i][j][k]*(rho[i][j][k] - rho[i][j][k-1])
                                + artificial_viscosity_on_recorder(m,i,j,k,viscosity_1,viscosity_2);
			w_predictor[i][j][k] = w[i][j][k] * Z_rec_2_prime + rho_predictor[i][j][k] / Z_rec_1_2_plus;
		}
	   }
	}
}
else {
/* next deal with points on the surface of the recorder using the surface normal info 
							- these have an acoustic impedance Z */
#ifdef CLUSTER
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor) private(i,j,k,m)
#endif

	for(m = 0; m < n_surface_points; m++) {
	   i = i_surface[m];
	   j = j_surface[m];
	   k = k_surface[m];
	   if(check_neighborhood(i,j,k) == COVERED_BY_LIP) {
		rho_predictor[i][j][k] = 0.0;
		u_predictor[i][j][k] = 0.0;
		v_predictor[i][j][k] = 0.0;
		w_predictor[i][j][k] = 0.0;
	   }
	   else {
		rho_predictor[i][j][k] = rho[i][j][k] + artificial_viscosity_on_recorder(m,i,j,k,viscosity_1,viscosity_2);
		if(x_hat[m] > 0.1) {
			rho_predictor[i][j][k] += 
				-(dt/dx_grid[i])*rho_air*(u[i+1][j][k] - u[i][j][k])
				-(dt/dx_grid[i])*u[i][j][k]*(rho[i+1][j][k] - rho[i][j][k]);
		}
		else if(x_hat[m] < -0.1) {
			rho_predictor[i][j][k] += 
				-(dt/dx_grid[i-1])*rho_air*(u[i][j][k] - u[i-1][j][k])
				-(dt/dx_grid[i-1])*u[i][j][k]*(rho[i][j][k] - rho[i-1][j][k]);
		}
		if(y_hat[m] > 0.1) {
			rho_predictor[i][j][k] += 
				-(dt/dy_grid[j])*rho_air*(v[i][j+1][k] - v[i][j][k])
				-(dt/dy_grid[j])*v[i][j][k]*(rho[i][j+1][k] - rho[i][j][k]);
		}
		else if(y_hat[m] < -0.1) {
			rho_predictor[i][j][k] += 
				-(dt/dy_grid[j-1])*rho_air*(v[i][j][k] - v[i][j-1][k])
				-(dt/dy_grid[j-1])*v[i][j][k]*(rho[i][j][k] - rho[i][j-1][k]);
		}
		if(z_hat[m] > 0.1) {
			rho_predictor[i][j][k] += 
				-(dt/dz_grid[k])*rho_air*(w[i][j][k+1] - w[i][j][k])
				-(dt/dz_grid[k])*w[i][j][k]*(rho[i][j][k+1] - rho[i][j][k]);
		}
		else if(z_hat[m] < -0.1) {
			rho_predictor[i][j][k] += 
				-(dt/dz_grid[k-1])*rho_air*(w[i][j][k] - w[i][j][k-1])
				-(dt/dz_grid[k-1])*w[i][j][k]*(rho[i][j][k] - rho[i][j][k-1]);
		}

// not sure if this will fix the problem with using surface_normal_info with moving lip but
// it should make this code act more like above without surface_normal_info
// added 9-5-16  -- was added above much earlier
		if((fabs(x_hat[m]) < 0.1) && (fabs(y_hat[m]) < 0.1)) {	// this surface is in x-y plane 
			u_predictor[i][j][k] = v_predictor[i][j][k] = 0.0;
		}
			
		if((fabs(y_hat[m]) < 0.1) && (fabs(z_hat[m]) < 0.1)) {	// this surface is in y-z plane 
			v_predictor[i][j][k] = w_predictor[i][j][k] = 0.0;
		}

		if((fabs(z_hat[m]) < 0.1) && (fabs(x_hat[m]) < 0.1)) {	// this surface is in z-x plane 
			w_predictor[i][j][k] = u_predictor[i][j][k] = 0.0;
		}

		vel_perp = rho_predictor[i][j][k] / Z_rec_1_2_plus;
		u_predictor[i][j][k] = u[i][j][k] * Z_rec_2_prime + vel_perp * x_hat[m]; 
		v_predictor[i][j][k] = v[i][j][k] * Z_rec_2_prime + vel_perp * y_hat[m]; 
		w_predictor[i][j][k] = w[i][j][k] * Z_rec_2_prime + vel_perp * z_hat[m]; 
	   }
	}
}

/* next deal with points on the boundaries - 
	these have an acoustic impedance Z = Z_1 + i omega Z_2 
   note that we don't have to worry about the corners
*/
	if(boundary_Z_flag == ON) {

#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
		for(j = 1; j <= j_max - 1; j++) {	// boundary plane at x = 0
			for(k = 1; k <= k_max - 1; k++) {
				v_predictor[0][j][k] = w_predictor[0][j][k] = 0.0;
				rho_predictor[0][j][k] = rho[0][j][k] 
							-(dt/dx_grid[0])*rho_air*(u[1][j][k] - u[0][j][k])
							-(dt/dx_grid[0])*u[0][j][k]*(rho[1][j][k] - rho[0][j][k])
               	                 + artificial_viscosity_on_boundary(0,j,k,viscosity_1,viscosity_2);
				u_predictor[0][j][k] 
					= u[0][j][k] * Z_bound_2_prime + rho_predictor[0][j][k] / Z_bound_1_2_plus;
			}
		}
#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
		for(j = 1; j <= j_max - 1; j++) {	// boundary at x = x_max
			for(k = 1; k <= k_max - 1; k++) {
				v_predictor[i_max][j][k] = w_predictor[i_max][j][k] = 0.0;
				rho_predictor[i_max][j][k] = rho[i_max][j][k]
					-(dt/dx_grid[i_max-1])*rho_air*(u[i_max][j][k] - u[i_max-1][j][k])
					-(dt/dx_grid[i_max-1])*u[i_max][j][k]*(rho[i_max][j][k]-rho[i_max-1][j][k])
               	                 + artificial_viscosity_on_boundary(i_max,j,k,viscosity_1,viscosity_2);
				u_predictor[i_max][j][k] 
				= u[i_max][j][k] * Z_bound_2_prime + rho_predictor[i_max][j][k] / Z_bound_1_2_plus;
			}
		}
#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
		for(i = 1; i <= i_max - 1; i++) {	// y = 0
			for(k = 1; k <= k_max - 1; k++) {
				u_predictor[i][0][k] = w_predictor[i][0][k] = 0.0;
				rho_predictor[i][0][k] = rho[i][0][k]
							-(dt/dy_grid[0])*rho_air*(v[i][1][k] - v[i][0][k])
							-(dt/dy_grid[0])*v[i][0][k]*(rho[i][1][k] - rho[i][0][k])
               	                 + artificial_viscosity_on_boundary(i,0,k,viscosity_1,viscosity_2);
				v_predictor[i][0][k] 
				= v[i][0][k] * Z_bound_2_prime + rho_predictor[i][0][k] / Z_bound_1_2_plus;
			}
		}
#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
		for(i = 1; i <= i_max - 1; i++) {	// y = y_max plane
			for(k = 1; k <= k_max - 1; k++) {
				u_predictor[i][j_max][k] = w_predictor[i][j_max][k] = 0.0;
				rho_predictor[i][j_max][k] = rho[i][j_max][k]
				 -(dt/dy_grid[j_max-1])*rho_air*(v[i][j_max][k] - v[i][j_max-1][k])
				 -(dt/dy_grid[j_max-1])*v[i][j_max][k]*(rho[i][j_max][k]-rho[i][j_max-1][k])
               	                 + artificial_viscosity_on_boundary(i,j_max,k,viscosity_1,viscosity_2);
				v_predictor[i][j_max][k] = 
				v[i][j_max][k] * Z_bound_2_prime + rho_predictor[i][j_max][k] / Z_bound_1_2_plus;
			}
		}
#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
		for(i = 1; i <= i_max - 1; i++) {	// z = 0 plane
			for(j = 1; j <= j_max - 1; j++) {
				u_predictor[i][j][0] = v_predictor[i][j][0] = 0.0;
				rho_predictor[i][j][0] = rho[i][j][0]
							-(dt/dz_grid[0])*rho_air*(w[i][j][1] - w[i][j][0])
							-(dt/dz_grid[0])*w[i][j][0]*(rho[i][j][1] - rho[i][j][0])
               	                 + artificial_viscosity_on_boundary(i,j,0,viscosity_1,viscosity_2);
				w_predictor[i][j][0] 
				= w[i][j][0] * Z_bound_2_prime + rho_predictor[i][j][0] / Z_bound_1_2_plus;
			}
		}
#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
		for(i = 1; i <= i_max - 1; i++) {	// z = z_max plane
			for(j = 1; j <= j_max - 1; j++) {
				u_predictor[i][j][k_max] = v_predictor[i][j][k_max] = 0.0;
				rho_predictor[i][j][k_max] = rho[i][j][k_max]
				 -(dt/dz_grid[k_max-1])*rho_air*(w[i][j][k_max] - w[i][j][k_max-1])
				 -(dt/dz_grid[k_max-1])*w[i][j][k_max]*(rho[i][j][k_max]-rho[i][j][k_max-1])
               	                 + artificial_viscosity_on_boundary(i,j,k_max,viscosity_1,viscosity_2);
				w_predictor[i][j][k_max] = 
				w[i][j][k_max] * Z_bound_2_prime + rho_predictor[i][j][k_max] / Z_bound_1_2_plus;
			}
		}
	}
}

/* now deal with rho in region where u is held constant	*/
	for(i = i_init_min; i <= i_init_max; i++) {
		for(j = j_init_min; j <= j_init_max; j++) {
			for(k = k_init_min; k <= k_init_max; k++) {
				rho_predictor[i][j][k] = rho_predictor[i-1][j][k] + (dx_grid[i-1]*rho_air/(c_s*c_s))*nu*second_deriv_y(u_predictor,i,j,k);
			}
		}
	}

{

#ifdef BENCHMARK
current_t = omp_get_wtime();
fprintf(fp_log,"starting fourth mac loop (6)\tt = %g\n",current_t - start_t);
#endif

#ifdef CLUSTER
#pragma omp collapse(3)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor) private(i,j,k)
#endif

	for(i = 1; i <= i_max-1; i++) {
		for(j = 1; j <= j_max-1; j++) {
			for(k = 1; k <= k_max-1; k++) {
/* for interior points, away from any boundaries			 */
				if((geometry[i][j][k] == OPEN)||(geometry[i][j][k] == GHOST)) {

				  rho[i][j][k] = 0.5 * (rho[i][j][k] + rho_predictor[i][j][k] 
-(dt/dx_grid[i]) * rho_air * (u_predictor[i+1][j][k] - u_predictor[i][j][k])  
-(dt/dx_grid[i]) * u_predictor[i][j][k] * (rho_predictor[i+1][j][k] - rho_predictor[i][j][k])
-(dt/dy_grid[j]) * rho_air * (v_predictor[i][j+1][k] - v_predictor[i][j][k])
-(dt/dy_grid[j]) * v_predictor[i][j][k] * (rho_predictor[i][j+1][k] - rho_predictor[i][j][k])
-(dt/dz_grid[k]) * rho_air * (w_predictor[i][j][k+1] - w_predictor[i][j][k])
-(dt/dz_grid[k]) * w_predictor[i][j][k] * (rho_predictor[i][j][k+1] - rho_predictor[i][j][k])
				  + artificial_viscosity(i,j,k,rho_predictor,rho_predictor,viscosity_1,viscosity_2));

				  u[i][j][k] = 0.5 * (u[i][j][k] + u_predictor[i][j][k]
-(dt/dx_grid[i]) * u_predictor[i][j][k] * (u_predictor[i+1][j][k] - u_predictor[i][j][k]) 
-(dt/dy_grid[j]) * v_predictor[i][j][k] * (u_predictor[i][j+1][k] - u_predictor[i][j][k]) 
-(dt/dz_grid[k]) * w_predictor[i][j][k] * (u_predictor[i][j][k+1] - u_predictor[i][j][k]) 
-(c_s*c_s/rho_air)*(dt/dx_grid[i]) * (rho_predictor[i+1][j][k] - rho_predictor[i][j][k])
+nu*dt*(second_deriv_x(u_predictor,i,j,k)+second_deriv_y(u_predictor,i,j,k)+second_deriv_z(u_predictor,i,j,k))
				  + artificial_viscosity(i,j,k,u_predictor,rho_predictor,viscosity_1,viscosity_2));
	
				  v[i][j][k] = 0.5 * (v[i][j][k] + v_predictor[i][j][k]
-(dt/dx_grid[i]) * u_predictor[i][j][k] * (v_predictor[i+1][j][k] - v_predictor[i][j][k]) 
-(dt/dy_grid[j]) * v_predictor[i][j][k] * (v_predictor[i][j+1][k] - v_predictor[i][j][k]) 
-(dt/dz_grid[k]) * w_predictor[i][j][k] * (v_predictor[i][j][k+1] - v_predictor[i][j][k]) 
-(c_s*c_s/rho_air)*(dt/dy_grid[j]) * (rho_predictor[i][j+1][k] - rho_predictor[i][j][k])
+nu*dt*(second_deriv_x(v_predictor,i,j,k)+second_deriv_y(v_predictor,i,j,k)+second_deriv_z(v_predictor,i,j,k))
				  + artificial_viscosity(i,j,k,v_predictor,rho_predictor,viscosity_1,viscosity_2));
	
				  w[i][j][k] = 0.5 * (w[i][j][k] + w_predictor[i][j][k]
-(dt/dx_grid[i]) * u_predictor[i][j][k] * (w_predictor[i+1][j][k] - w_predictor[i][j][k]) 
-(dt/dy_grid[j]) * v_predictor[i][j][k] * (w_predictor[i][j+1][k] - w_predictor[i][j][k]) 
-(dt/dz_grid[k]) * w_predictor[i][j][k] * (w_predictor[i][j][k+1] - w_predictor[i][j][k]) 
-(c_s*c_s/rho_air)*(dt/dz_grid[k]) * (rho_predictor[i][j][k+1] - rho_predictor[i][j][k])
+nu*dt*(second_deriv_x(w_predictor,i,j,k)+second_deriv_y(w_predictor,i,j,k)+second_deriv_z(w_predictor,i,j,k))
				  + artificial_viscosity(i,j,k,w_predictor,rho_predictor,viscosity_1,viscosity_2));
				}
			}
		}
	}
}

{
/* finally - update points on surface of recorder */
#ifdef CLUSTER
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor) private(i,j,k,m)
#endif

        for(m = 0; m < n_boundary; m++) {
                i = x_boundary[m];
                j = y_boundary[m];
                k = z_boundary[m];
                u[i][j][k] = u_predictor[i][j][k];
                v[i][j][k] = v_predictor[i][j][k];
                w[i][j][k] = w_predictor[i][j][k];
                rho[i][j][k] = rho_predictor[i][j][k];
        }

/* update points on the boundaries - note that we don't have to worry about the corners
*/

        if(boundary_Z_flag == ON) {
#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
                for(j = 1; j <= j_max - 1; j++) {       // x = 0 plane
                	for(k = 1; k <= k_max - 1; k++) {       
                                rho[0][j][k] = rho_predictor[0][j][k];
                                u[0][j][k] = u_predictor[0][j][k];
                                v[0][j][k] = v_predictor[0][j][k];
                                w[0][j][k] = w_predictor[0][j][k];
			}
                }
#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
                for(j = 1; j <= j_max - 1; j++) {       // x = x_max plane
                	for(k = 1; k <= k_max - 1; k++) {       
                                rho[i_max][j][k] = rho_predictor[i_max][j][k];
                                u[i_max][j][k] = u_predictor[i_max][j][k];
                                v[i_max][j][k] = v_predictor[i_max][j][k];
                                w[i_max][j][k] = w_predictor[i_max][j][k];
			}
                }
#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
                for(i = 1; i <= i_max - 1; i++) {       // y = 0 plane
                	for(k = 1; k <= k_max - 1; k++) {       
                                rho[i][0][k] = rho_predictor[i][0][k];
                                v[i][0][k] = v_predictor[i][0][k];
                                u[i][0][k] = u_predictor[i][0][k];
                                w[i][0][k] = w_predictor[i][0][k];
			}
                }
#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
                for(i = 1; i <= i_max - 1; i++) {       // y = y_max plane
                	for(k = 1; k <= k_max - 1; k++) {       
                                rho[i][j_max][k] = rho_predictor[i][j_max][k];
                                v[i][j_max][k] = v_predictor[i][j_max][k];
                                u[i][j_max][k] = u_predictor[i][j_max][k];
                                w[i][j_max][k] = w_predictor[i][j_max][k];
			}
                }
#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
                for(i = 1; i <= i_max - 1; i++) {       // z = 0 plane
                	for(j = 1; j <= j_max - 1; j++) {       
                                rho[i][j][0] = rho_predictor[i][j][0];
                                w[i][j][0] = w_predictor[i][j][0];
                                u[i][j][0] = u_predictor[i][j][0];
                                v[i][j][0] = v_predictor[i][j][0];
			}
                }
#ifdef CLUSTER
#pragma omp collapse(2)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
                for(i = 1; i <= i_max - 1; i++) {       // z = z_max plane
                	for(j = 1; j <= j_max - 1; j++) {       
                                rho[i][j][k_max] = rho_predictor[i][j][k_max];
                                w[i][j][k_max] = w_predictor[i][j][k_max];
                                u[i][j][k_max] = u_predictor[i][j][k_max];
                                v[i][j][k_max] = v_predictor[i][j][k_max];
			}
                }
        }
}

/* now deal with rho in region where u is held constant	*/
	for(i = i_init_min; i <= i_init_max; i++) {
		for(j = j_init_min; j <= j_init_max; j++) {
			for(k = k_init_min; k <= k_init_max; k++) {
				rho[i][j][k] = rho[i-1][j][k] + (dx_grid[i-1]*rho_air/(c_s*c_s))*nu*second_deriv_y(u,i,j,k); 
			}
		}
	}

// now test for nan and record problem locations in log_file - if any are found then exit
/*
 */
#ifdef CLUSTER
#pragma omp collapse(3)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
        for(i = 1; i <= i_max-1; i++) {
                for(j = 1; j <= j_max-1; j++) {
                        for(k = 1; k <= k_max-1; k++) {
                                if(fabs(rho[i][j][k]) > 1e3) {
                                        fprintf(fp_log,"(c)rho too large %g\t%d\t%d\t%d\n",rho[i][j][k],i,j,k);
                                        nan_flag = YES;
					diag_dump(i,j,k);
                                }
                        }
                }
        }

//fprintf(fp_log,"in mac (7)\tt = %g\n",t);
//fflush(fp_log);

	update_velocity_on_lip_surfaces2();

//fprintf(fp_log,"in mac (8)\tt = %g\n",t);

//fflush(fp_log);
	save_lip_predictors();

//fprintf(fp_log,"in mac (9)\tt = %g\n",t);
//fflush(fp_log);

	move_lips();

//fprintf(fp_log,"in mac (10)\tt = %g\n",t);
//fflush(fp_log);

	update_lip_geometry_v2(QUIET);

//fprintf(fp_log,"in mac (11)\tt = %g\n",t);
//fflush(fp_log);

	calc_site_weights();

//fprintf(fp_log,"in mac (12)\tt = %g\n",t);
//fflush(fp_log);

{

#ifdef BENCHMARK
current_t = omp_get_wtime();
fprintf(fp_log,"finished fourth mac loop (7)\tt = %g\n",current_t - start_t);
#endif

	t += 2 * dt;

	if((t <= t_blow_transient) || 
			((t > t_stop_blowing) && (t <= t_stop_blowing+t_ramp_down))) {
/*
 #ifdef CLUSTER
 #pragma omp collapse(3)
 #pragma omp parallel for shared(u,u_predictor,rho) private(i,j,k)
 #endif
*/

		for(i = i_init_min; i <= i_init_max; i++) {
			for(j = j_init_min; j <= j_init_max; j++) {
				for(k = k_init_min; k <= k_init_max; k++) {
					u_predictor[i][j][k] = u[i][j][k] = blowing_velocity(t,i,j,k);
					v[i][j][k] = w[i][j][k] = v_predictor[i][j][k] = w_predictor[i][j][k] = 0.0;
				}
			}
		}
	}

	for(i = i_init_min; i <= i_init_max; i++) {
		for(j = j_init_min; j <= j_init_max; j++) {
			for(k = k_init_min; k <= k_init_max; k++) {
				if(geometry[i][j][k] != INIT_POINT) {
					fprintf(fp_log,"error C initializing rho i,j,k (%d %d %d) not in init region\n",i,j,k);
					my_exit();
				}
				rho[i][j][k] = rho[i-1][j][k] + (dx_grid[i-1]*rho_air/(c_s*c_s))*nu*second_deriv_y(u,i,j,k);
			}
		}
	}

}
{

	if(t >= t_stop_blowing + t_ramp_down) {
#ifdef CLUSTER
#pragma omp collapse(3)
#pragma omp parallel for shared(u,v,rho,rho_predictor,geometry) private(i,j,k)
#endif
		for(i = i_init_min; i <= i_init_max; i++) {
			for(j = j_init_min; j <= j_init_max; j++) {
				for(k = k_init_min; k <= k_init_max; k++) {
					geometry[i][j][k] = OPEN; 
				}
			}
		}
	}
}

	if(accum_flag == YES) {
		accum_filtering_data();
		++n_accum_buffer_count;
	}

	for(i = 1; i <= n_record_sound; i++) {
		rho_t_sum[i] += rho[i_record[i]][j_record[i]][k_record[i]];
			vel_t_sum[i] += u[i_record[i]][j_record[i]][k_record[i]];
	}

	lip_left_x_sum += di_center[LEFT][CURRENT];
	lip_left_y_sum += dj_center[LEFT][CURRENT];
	lip_right_x_sum += di_center[RIGHT][CURRENT];
	lip_right_y_sum += dj_center[RIGHT][CURRENT];
	lip_width_sum += j_center[RIGHT][CURRENT] - j_width[RIGHT] + dj_center[RIGHT][CURRENT] 
        	- (j_center[LEFT][CURRENT] + j_width[LEFT] + dj_center[LEFT][CURRENT]);

	lip_left_y_interior_sum += dj_center_interior[LEFT][CURRENT];
	lip_right_y_interior_sum += dj_center_interior[RIGHT][CURRENT];
	lip_width_interior_sum += j_origin[RIGHT] - j_width[RIGHT] + 2.0*dj_center_interior[RIGHT][CURRENT]
        	- (j_origin[LEFT] + j_width[LEFT] + 2.0*dj_center_interior[LEFT][CURRENT]);
	lip_left_x_interior_sum += di_center_interior[LEFT][CURRENT];
	lip_right_x_interior_sum += di_center_interior[RIGHT][CURRENT];

// NOTE the minus signs here - added for runs 1066c and later!!!
	lip_force_y_sum[LEFT] -= f_pressure_y[LEFT];
	lip_force_y_sum[RIGHT] -= f_pressure_y[RIGHT];
	lip_force_x_sum[LEFT] -= f_pressure_x[LEFT];
	lip_force_x_sum[RIGHT] -= f_pressure_x[RIGHT];

	rho_mid_lip_sum += rho[i_mid_lip(RIGHT)][(int)(j_origin[LEFT]+j_origin[RIGHT])/2][k_mid];
	vel_mid_lip_sum += u[i_mid_lip(RIGHT)][(int)(j_origin[LEFT]+j_origin[RIGHT])/2][k_mid];
	rho_entrance_lip_sum += rho[i_entrance_lip(RIGHT)-1][(int)(j_origin[LEFT]+j_origin[RIGHT])/2][k_mid];
	rho_exit_lip_sum += rho[i_exit_lip(RIGHT)+2][(int)(j_origin[LEFT]+j_origin[RIGHT])/2][k_mid];
	vel_entrance_lip_sum += u[i_entrance_lip(RIGHT)-1][(int)(j_origin[LEFT]+j_origin[RIGHT])/2][k_mid];
	vel_exit_lip_sum += u[i_exit_lip(RIGHT)+2][(int)(j_origin[LEFT]+j_origin[RIGHT])/2][k_mid];
	rho_lip_upstream_edge_sum += rho[(int)(i_upstream_lip_middle(RIGHT))-1][(int)(j_center[LEFT][CURRENT])][k_mid];
	rho_lip_downstream_edge_sum += rho[(int)(i_downstream_lip_middle(RIGHT))+2][(int)(j_center[LEFT][CURRENT])][k_mid];

	t_sum += t;

//	fprintf(fp_log,"t = %g\n",t);
//	fflush(fp_log);

	k2++;
	if(k2 >= n_record_2) {
		t_sum /= k2;
		for(i = 1; i <= n_record_sound; i++) {
			fprintf(fp_rho_t[i],"%g\t%g\n",t_sum,rho_t_sum[i]/k2);
			fflush(fp_rho_t[i]);
			fprintf(fp_vel_t[i],"%g\t%g\n",t_sum,vel_t_sum[i]/k2);
			fflush(fp_vel_t[i]);
		}

		fprintf(fp_lip_left_x,"%g\t%g\n",t_sum,lip_left_x_sum/k2);
		fprintf(fp_lip_left_y,"%g\t%g\n",t_sum,lip_left_y_sum/k2);
		fprintf(fp_lip_right_x,"%g\t%g\n",t_sum,lip_right_x_sum/k2);
		fprintf(fp_lip_right_y,"%g\t%g\n",t_sum,lip_right_y_sum/k2);
		fprintf(fp_lip_width,"%g\t%g\n",t_sum,lip_width_sum/k2);

		fprintf(fp_lip_left_interior_y,"%g\t%g\n",t_sum,lip_left_y_interior_sum/k2);
		fprintf(fp_lip_right_interior_y,"%g\t%g\n",t_sum,lip_right_y_interior_sum/k2);
		fprintf(fp_lip_width_interior,"%g\t%g\n",t_sum,lip_width_interior_sum/k2);
		fprintf(fp_lip_left_interior_x,"%g\t%g\n",t_sum,lip_left_x_interior_sum/k2);
		fprintf(fp_lip_right_interior_x,"%g\t%g\n",t_sum,lip_right_x_interior_sum/k2);

		fprintf(fp_lip_force_y[LEFT],"%g\t%g\n",t_sum,lip_force_y_sum[LEFT]/k2);
		fprintf(fp_lip_force_y[RIGHT],"%g\t%g\n",t_sum,lip_force_y_sum[RIGHT]/k2);
		fprintf(fp_lip_force_x[LEFT],"%g\t%g\n",t_sum,lip_force_x_sum[LEFT]/k2);
		fprintf(fp_lip_force_x[RIGHT],"%g\t%g\n",t_sum,lip_force_x_sum[RIGHT]/k2);

		fprintf(fp_rho_mid_lip,"%g\t%g\n",t_sum,rho_mid_lip_sum/k2);
		fprintf(fp_vel_mid_lip,"%g\t%g\n",t_sum,vel_mid_lip_sum/k2);
		fprintf(fp_rho_entrance_lip,"%g\t%g\n",t_sum,rho_entrance_lip_sum/k2);
		fprintf(fp_rho_exit_lip,"%g\t%g\n",t_sum,rho_exit_lip_sum/k2);
		fprintf(fp_vel_entrance_lip,"%g\t%g\n",t_sum,vel_entrance_lip_sum/k2);
		fprintf(fp_vel_exit_lip,"%g\t%g\n",t_sum,vel_exit_lip_sum/k2);
		fprintf(fp_rho_lip_upstream_edge,"%g\t%g\n",t_sum,rho_lip_upstream_edge_sum/k2);
		fprintf(fp_rho_lip_downstream_edge,"%g\t%g\n",t_sum,rho_lip_downstream_edge_sum/k2);

		fprintf(fp_log,"t = %g\n",t);
//		fprintf(fp_log,"\ti_entrance/mid/exit = %d / %d / %d\n",i_entrance_lip(RIGHT),i_mid_lip(RIGHT),i_exit_lip(RIGHT));
//		fprintf(fp_log,"\ti_upstream-1/downstream+2 = %d / %d / %d\n",(int)(i_upstream_lip_middle(RIGHT)-1),(int)(i_downstream_lip_middle(RIGHT)+2));
//		fprintf(fp_log,"\ti_current/origin = %g / %g\n",i_center[RIGHT][CURRENT],i_origin[RIGHT]);
//		fprintf(fp_log,"old i_entrance/mid/exit = %d / %d / %d\n\n",i_mid_lip()-(int)i_width[LEFT],i_mid_lip(),i_mid_lip()+(int)i_width[LEFT]);
		fflush(fp_log);

		fflush(fp_lip_left_x);
		fflush(fp_lip_left_y);
		fflush(fp_lip_right_x);
		fflush(fp_lip_right_y);
		fflush(fp_lip_width);

		fflush(fp_lip_left_interior_y);
		fflush(fp_lip_right_interior_y);
		fflush(fp_lip_width_interior);
		fflush(fp_lip_left_interior_x);
		fflush(fp_lip_right_interior_x);

		fflush(fp_lip_force_y[LEFT]);
		fflush(fp_lip_force_y[RIGHT]);
		fflush(fp_lip_force_x[LEFT]);
		fflush(fp_lip_force_x[RIGHT]);
		fflush(fp_rho_mid_lip);
		fflush(fp_vel_mid_lip);
		fflush(fp_rho_entrance_lip);
		fflush(fp_rho_exit_lip);
		fflush(fp_vel_entrance_lip);
		fflush(fp_vel_exit_lip);
		fflush(fp_rho_lip_upstream_edge);
		fflush(fp_rho_lip_downstream_edge);

		k2 = 0;
		for(i = 1; i <= n_record_sound; i++) {
			rho_t_sum[i] = 0.0;
			vel_t_sum[i] = 0.0;
		}
		lip_left_x_sum = lip_left_y_sum = lip_right_x_sum = 
			lip_right_y_sum = lip_width_sum = 0.0;

		lip_left_y_interior_sum = lip_right_y_interior_sum = lip_width_interior_sum = 0.0;
		lip_left_x_interior_sum = lip_right_x_interior_sum = 0.0;

		lip_force_y_sum[LEFT] = lip_force_y_sum[RIGHT] = lip_force_x_sum[LEFT] = lip_force_x_sum[RIGHT] = 0.0;

		rho_lip_upstream_edge_sum = rho_lip_downstream_edge_sum 
			= rho_mid_lip_sum = vel_mid_lip_sum = vel_entrance_lip_sum = vel_exit_lip_sum =  0.0;
		rho_entrance_lip_sum = rho_exit_lip_sum = 0.0;

		t_sum = 0.0;
		rho_max = x_max = y_max = z_max = 0.0;

/*
#ifdef CLUSTER
#pragma omp collapse(3)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
        	for(i = 1; i <= i_max-1; i++) {
               		for(j = 1; j <= j_max-1; j++) {
               	        	for(k = 1; k <= k_max-1; k++) {
               	                	if(fabs(rho[i][j][k]) > fabs(rho_max)) {
                                        	rho_max = rho[i][j][k];
                                        	x_max = x_grid[i];
                                        	y_max = y_grid[j];
                                        	z_max = z_grid[k];
						i_big = i;
						j_big = j;
						k_big = k;
               	                 	}
               	         	}
               	 	}
        	}
		fprintf(fp_log,"at t = %g\trho(max) = %g at (%g, %g, %g) (%d %d %d)\n",t,rho_max,x_max,y_max,z_max,i_big,j_big,k_big);
		fflush(fp_log);

// now test for nan and record problem locations in log_file - if any are found then exit
#ifdef CLUSTER
#pragma omp collapse(3)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif
        	for(i = 1; i <= i_max-1; i++) {
               		for(j = 1; j <= j_max-1; j++) {
                        	for(k = 1; k <= k_max-1; k++) {
                                	if(fabs(rho[i][j][k]) > 1e3) {
                                        	fprintf(fp_log,"(d)rho too large %g\t%d\t%d\t%d\n",rho[i][j][k],i,j,k);
                                        	nan_flag = YES;
//						diag_dump(i,j,k);
                                	}
                        	}
                	}
        	}
        	if(nan_flag == YES) {
display_cell_values("208");
display_lip_region("display (99) just before exiting");
//                	record_data2(n_file_num);
                	my_exit();
        	}

*/

	}

	if((t >= t_next_map) && (t < t_map_end)) {
		accum_map(rho_buf,rho);
		accum_map(u_buf,u);
		accum_map(v_buf,v);
		accum_map(w_buf,w);	// add this 08_11_12 
		k_map++;
	}

	if((t >= t_next_record) && (t < t_map_end)) {
		normalize_map(rho_buf,k_map);
		normalize_map(u_buf,k_map);
		normalize_map(v_buf,k_map);
		normalize_map(w_buf,k_map);	// add this 08_11_12 
		record_data(n_file_num,rho_max);

//		fprintf(fp_log,"t = %g  pressure vals\n",t);
//		fprintf(fp_log,"f_pressure_x left / right = %g/%g\tf_pressure_y left / right = %g/%g\n",
//			f_pressure_x[LEFT],f_pressure_x[RIGHT],f_pressure_y[LEFT],f_pressure_y[RIGHT]);
//		sprintf(tmp4,"t = %g",t);
//		display_cell_values(tmp4);
//		display_lip_region("\n");

		k_map = 0;
		t_next_record += t_record_map;
		t_next_map = t_next_record - t_map_ave;
		reset_map(rho_buf);
		reset_map(u_buf);
		reset_map(v_buf);
		reset_map(w_buf);	// add this 08_11_12 
		n_file_num++;
	}

	if(t >= t_next_restart_save) {
		save_for_restart();
		t_next_restart_save += t_restart_save_interval;
	}
	if(t >= t_viscosity_start) {
		viscosity_1 = viscosity_1_0;
		viscosity_2 = viscosity_2_0;
	}
	
	if((accum_flag == YES) && (t > t_accum_end)) {
		t = reset_filtering_data(n_accum_buffer_count,t);
		zero_filtering_data();
		n_accum_buffer_count = 0;
		t_next_accum += t_accum_interval;
		t_accum_end = t_next_accum + t_accum;
		accum_flag = NO;

		// also save lip map now
		display_lip_region("display(5) current lip map\n");
		display_cell_values("current site values");
	}
	else if((accum_flag == NO) && (t > t_next_accum)) {
		accum_flag = YES;
		fprintf(fp_log,"starting to filter rho, u, and v at t = %g\n",t);
		fflush(fp_log);
	}


#ifdef BENCHMARK
current_t = omp_get_wtime();
fprintf(fp_log,"finished loop %d in run() (8)\tt = %g\n\n",n_benchmark,current_t - start_t);
++n_benchmark;
if(n_benchmark >= 10) exit(0);
#endif

   }
	for(i = 1; i <= n_record_sound; i++) {
		fclose(fp_rho_t[i]);
		fclose(fp_vel_t[i]);
	}

	fclose(fp_lip_width);
	fclose(fp_lip_force_y[LEFT]);
	fclose(fp_lip_force_y[RIGHT]);
	fclose(fp_lip_force_x[LEFT]);
	fclose(fp_lip_force_x[RIGHT]);
	fclose(fp_rho_mid_lip);
	fclose(fp_vel_mid_lip);
	fclose(fp_rho_entrance_lip);
	fclose(fp_rho_exit_lip);
	fclose(fp_vel_entrance_lip);
	fclose(fp_vel_exit_lip);
	fclose(fp_rho_lip_upstream_edge);
	fclose(fp_rho_lip_downstream_edge);

   return(0);
}

int
normalize_map(float ***q,int n)
{
	int i,j,k;

	for(i = 0; i <= i_max; i++) {
		for(j = 0; j <= j_max; j++) {
			for(k = 0; k <= k_max; k++) {
				q[i][j][k] /= (double)n;
			}
		}
	}
	return(0);	
}

/*
 *	accumulate values in the buffers used to average the maps for rho, u, and v
 */
int
accum_map(float ***q1, float ***q2)
{
	int i,j,k;

	for(i = 0; i <= i_max; i++) {
		for(j = 0; j <= j_max; j++) {
			for(k = 0; k <= k_max; k++) {
				q1[i][j][k] += q2[i][j][k];
			}
		}
	}
	return(0);	
}

/*
 *	reset to zero the buffers used to average the maps for rho, u, and v
 */
int
reset_map(float ***q)
{
	int i,j,k;

	for(i = 0; i <= i_max; i++) {
		for(j = 0; j <= j_max; j++) {
			for(k = 0; k <= k_max; k++) {
				q[i][j][k] = 0.0; 
			}
		}
	}
	return(0);	
}

/* 
 * record full results for rho, u, and v as a function of position
 * put results in results_directory_full_path and have files numbered
 *
 * use ONE file to hold everything - a change from the 2D calcs
 *
 * value of t for each file is in file t_record_map.dat
 */
int
record_data(n,r_max)
int n;
double r_max;
{
	FILE *fp_save;
	int i,j,k;
	char save_file[300];

	sprintf(save_file,"%s/%s.rho_u_v_w.dat.%d",scratch_directory,results_directory,n);

	fp_save = fopen(save_file,"w");
	for(i = 0; i <= i_max; i++) {
		for(j = 0; j <= j_max; j++) {
			for(k = 0; k <= k_max; k++) {
					fprintf(fp_save,"%0.4g\t%0.4g\t%0.4g\t%0.4g\t%0.4g\t%0.4g\t%0.4g\n",
						x_grid[i],y_grid[j],z_grid[k],rho_buf[i][j][k],
						u_buf[i][j][k],v_buf[i][j][k],w_buf[i][j][k]);
			}
		}
	}

	fprintf(fp_t,"%g\n",t);
	fflush(fp_t);
   	fclose(fp_save);

	record_data_lip(n);

	return(0);
}


/* 
 * use a separate file to the map data on the edges of the lips (fp_save_lip)
 *
 * value of t for each file is in file t_record_map.dat
 *
 * D_GRID is the factor by which the grid is made finer inside the lips
 * RHO_LIP is the density to assign to the lips
 */

#define D_GRID	0.2
#define RHO_LIP	-1.0

int
record_data_lip(n)
int n;
{
	FILE *fp_save_lip;
	int i,j,k;
	char save_file[300];
	double j_edge[2],i_double_min,i_double_max;
	double i_double,j_double,x_lip,y_lip,z_lip,rho_lip,u_lip,v_lip,w_lip;
	double j_sloping_edge[2];
	double di,dj;

	sprintf(save_file,"%s/%s.lip_rho_u_v_w.dat.%d",scratch_directory,results_directory,n);
	fp_save_lip = fopen(save_file,"w");

	for(i_double = i_lip_region_min-40; i_double <= i_lip_region_max+10*i_width[LEFT]; i_double += D_GRID) {
		for(j_double = j_lip_region_min-30; j_double <= j_lip_region_max+30; j_double += D_GRID) {
			for(k = k_lip_region_min; k <= k_lip_region_max; k++) {
				i = i_double;	// will round down
				di = i_double - i;	// get fraction off the grid point
				j = j_double;	// will round down
				dj = j_double - j;	// get fraction off the grid point
				rho_lip = rho_buf[i][j][k]+di*(rho_buf[i+1][j][k]-rho_buf[i][j][k])+dj*(rho_buf[i][j+1][k]-rho_buf[i][j][k]);
				u_lip = u_buf[i][j][k]+di*(u_buf[i+1][j][k]-u_buf[i][j][k])+dj*(u_buf[i][j+1][k]-u_buf[i][j][k]);
				v_lip = v_buf[i][j][k]+di*(v_buf[i+1][j][k]-v_buf[i][j][k])+dj*(v_buf[i][j+1][k]-v_buf[i][j][k]);
				w_lip = w_buf[i][j][k]+di*(w_buf[i+1][j][k]-w_buf[i][j][k])+dj*(w_buf[i][j+1][k]-w_buf[i][j][k]);
//				if((geometry[i][j][k] == SOLID) && (geometry[i+1][j][k] == SOLID)  
//					&& (geometry[i][j+1][k] == SOLID) && (geometry[i+1][j+1][k] == SOLID)) {
//					rho_lip = RHO_LIP;
//					u_lip = v_lip = w_lip = 0.0;
//				}
				if((j_double > j_pivot[LEFT]) && 
					(j_double <= j_center[LEFT][CURRENT] + j_width[LEFT] + dj_center[LEFT][CURRENT])) { // on the left side
					i_double_min = i_leading_edge_double(LEFT,j_double);
					i_double_max = i_trailing_edge_double(LEFT,j_double);
					if((i_double >= i_double_min) && (i_double <= i_double_max)) {
						rho_lip = RHO_LIP;
						u_lip = v_lip = w_lip = 0.0;
					}
				}
				else if((j_double < j_pivot[RIGHT]) && 
					(j_double >= j_center[RIGHT][CURRENT] - j_width[RIGHT] + dj_center[RIGHT][CURRENT])) { // on the right side
					i_double_min = i_leading_edge_double(RIGHT,j_double);
					i_double_max = i_trailing_edge_double(RIGHT,j_double);
					if((i_double >= i_double_min) && (i_double <= i_double_max)) {
						rho_lip = RHO_LIP;
						u_lip = v_lip = w_lip = 0.0;
					}
				}
				x_lip = x_grid[(int)i_double] + (i_double-(int)i_double)*dx_grid[(int)i_double];
				y_lip = y_grid[(int)j_double] + (j_double-(int)j_double)*dy_grid[(int)j_double];
				z_lip = z_grid[k];
				fprintf(fp_save_lip,"%0.5g\t%0.5g\t%0.5g\t%g\t%g\t%g\t%g\n",x_lip,y_lip,z_lip,rho_lip,u_lip,v_lip,w_lip);
			}
		}
	}

   	fclose(fp_save_lip);

	return(0);
}

int
record_data2(n)
int n;
{
        FILE *fp_save;
        int i,j,k;
        char save_file[300];

        sprintf(save_file,"%s/%s.rho_u_v_w.dat.%d",scratch_directory,results_directory,n);

        fp_save = fopen(save_file,"w");
        for(i = 0; i <= i_max; i++) {
                for(j = 0; j <= j_max; j++) {
                        for(k = 0; k <= k_max; k++) {
                                fprintf(fp_save,"%g\t%g\t%g\t%g\t%g\t%g\t%g\n",
                                        x_grid[i],y_grid[j],z_grid[k],rho[i][j][k],
                                        u[i][j][k],v[i][j][k],w[i][j][k]);
                        }
                }
        }

        fprintf(fp_t,"%g\n",t);
        fflush(fp_t);
        fclose(fp_save);

	return(0);
}

/*
 *	need a routine to find and classify boundary points
 *
 *	have 7 cases to consider on surface of recorder - these are
 *	reflecting/non-slip surfaces and the computation of u, v, w, and rho
 *	at these points must be treated specially, different from the 
 *	standard MacCormack algorithm
 *
 *	case 1: a surface perpendicular to x with air on the +x side == XUP
 *	case 2: a surface perpendicular to x with air on the -x side == XDOWN
 *	case 3: a surface perpendicular to y with air on the +y side == YUP
 *	case 4: a surface perpendicular to y with air on the -y side == YDOWN
 *	case 5: a surface perpendicular to z with air on the +z side == ZUP
 *	case 6: a surface perpendicular to z with air on the -z side == ZDOWN
 *	case 7: a convex corner                               == CORNER
 *
 *	this classification scheme is based on surface normals, which is different
 *	from scheme used in the 2D work
 */

int
boundary() 
{
	int i,j,k;
	int n;

	n = 0;	/* number of special boundary points on recorder */

	for(i = 1; i <= i_max-1; i++) {
		for(j = 1; j <= j_max-1; j++) {
			for(k = 1; k <= k_max-1; k++) {
				if(geometry[i][j][k] == SOLID) { /* have found a recorder point */
/* case 1 */				if((geometry[i+1][j][k] == OPEN)
						&& (geometry[i-1][j][k] == SOLID)
						&& (geometry[i][j+1][k] == SOLID)
						&& (geometry[i][j-1][k] == SOLID)
						&& (geometry[i][j][k-1] == SOLID)
						&& (geometry[i][j][k+1] == SOLID)) {
						x_boundary[n] = i;
						y_boundary[n] = j;
						z_boundary[n] = k;
						boundary_flag[n] = XUP;
						++n;
					}
/* case 2 */				else if((geometry[i+1][j][k] == SOLID)
						&& (geometry[i-1][j][k] == OPEN)
						&& (geometry[i][j+1][k] == SOLID)
						&& (geometry[i][j-1][k] == SOLID) 
						&& (geometry[i][j][k-1] == SOLID)
						&& (geometry[i][j][k+1] == SOLID)) {
						x_boundary[n] = i;
						y_boundary[n] = j;
						z_boundary[n] = k;
						boundary_flag[n] = XDOWN;
						++n;
					}
/* case 3 */				else if((geometry[i+1][j][k] == SOLID)
						&& (geometry[i-1][j][k] == SOLID)
						&& (geometry[i][j-1][k] == SOLID)
						&& (geometry[i][j+1][k] == OPEN)
						&& (geometry[i][j][k-1] == SOLID)
						&& (geometry[i][j][k+1] == SOLID)) {
						x_boundary[n] = i;
						y_boundary[n] = j;
						z_boundary[n] = k;
						boundary_flag[n] = YUP;
						++n;
					}
/* case 4 */				else if((geometry[i+1][j][k] == SOLID)
						&& (geometry[i-1][j][k] == SOLID)
						&& (geometry[i][j-1][k] == OPEN)
						&& (geometry[i][j+1][k] == SOLID)
						&& (geometry[i][j][k-1] == SOLID)
						&& (geometry[i][j][k+1] == SOLID)) {
						x_boundary[n] = i;
						y_boundary[n] = j;
						z_boundary[n] = k;
						boundary_flag[n] = YDOWN;
						++n;
					}
/* case 5 */				else if((geometry[i+1][j][k] == SOLID)
						&& (geometry[i-1][j][k] == SOLID)
						&& (geometry[i][j-1][k] == SOLID)
						&& (geometry[i][j+1][k] == SOLID)
						&& (geometry[i][j][k-1] == SOLID)
						&& (geometry[i][j][k+1] == OPEN)) {
						x_boundary[n] = i;
						y_boundary[n] = j;
						z_boundary[n] = k;
						boundary_flag[n] = ZUP;
						++n;
					}
/* case 6 */				else if((geometry[i+1][j][k] == SOLID)
						&& (geometry[i-1][j][k] == SOLID)
						&& (geometry[i][j-1][k] == SOLID)
						&& (geometry[i][j+1][k] == SOLID)
						&& (geometry[i][j][k-1] == OPEN)
						&& (geometry[i][j][k+1] == SOLID)) {
						x_boundary[n] = i;
						y_boundary[n] = j;
						z_boundary[n] = k;
						boundary_flag[n] = ZDOWN;
						++n;
					}
/* case 7 */				else if((geometry[i+1][j][k] == SOLID)
/* there are actually */			&& (geometry[i-1][j][k] == OPEN)
/* 8 different types  */			&& (geometry[i][j+1][k] == SOLID)
/* of case 7          */			&& (geometry[i][j-1][k] == OPEN)
						&& (geometry[i][j][k+1] == OPEN)
						&& (geometry[i][j][k-1] == SOLID)) {
/* they are all treated as */			x_boundary[n] = i;
/* having OPEN geometry */			y_boundary[n] = j;
						z_boundary[n] = k;
						boundary_flag[n] = CORNER;
						++n;
					}
					else if((geometry[i+1][j][k] == OPEN)
						&& (geometry[i-1][j][k] == SOLID)
						&& (geometry[i][j+1][k] == SOLID)
						&& (geometry[i][j-1][k] == OPEN)
						&& (geometry[i][j][k+1] == OPEN)
						&& (geometry[i][j][k-1] == SOLID)) {
						x_boundary[n] = i;
						y_boundary[n] = j;
						z_boundary[n] = k;
						boundary_flag[n] = CORNER;
						++n;
					}
					else if((geometry[i+1][j][k] == OPEN)
						&& (geometry[i-1][j][k] == SOLID)
						&& (geometry[i][j+1][k] == SOLID)
						&& (geometry[i][j-1][k] == OPEN)
						&& (geometry[i][j][k+1] == SOLID)
						&& (geometry[i][j][k-1] == OPEN)) {
						x_boundary[n] = i;
						y_boundary[n] = j;
						z_boundary[n] = k;
						boundary_flag[n] = CORNER;
						++n;
					}
					else if((geometry[i+1][j][k] == SOLID)
						&& (geometry[i-1][j][k] == OPEN)
						&& (geometry[i][j+1][k] == SOLID)
						&& (geometry[i][j-1][k] == OPEN)
						&& (geometry[i][j][k+1] == SOLID)
						&& (geometry[i][j][k-1] == OPEN)) {
						x_boundary[n] = i;
						y_boundary[n] = j;
						z_boundary[n] = k;
						boundary_flag[n] = CORNER;
						++n;
					}
					else if((geometry[i+1][j][k] == SOLID)
						&& (geometry[i-1][j][k] == OPEN)
						&& (geometry[i][j+1][k] == OPEN)
						&& (geometry[i][j-1][k] == SOLID)
						&& (geometry[i][j][k+1] == OPEN)
						&& (geometry[i][j][k-1] == SOLID)) {
						x_boundary[n] = i;
						y_boundary[n] = j;
						z_boundary[n] = k;
						boundary_flag[n] = CORNER;
						++n;
					}
					else if((geometry[i+1][j][k] == OPEN)
						&& (geometry[i-1][j][k] == SOLID)
						&& (geometry[i][j+1][k] == OPEN)
						&& (geometry[i][j-1][k] == SOLID)
						&& (geometry[i][j][k+1] == OPEN)
						&& (geometry[i][j][k-1] == SOLID)) {
						x_boundary[n] = i;
						y_boundary[n] = j;
						z_boundary[n] = k;
						boundary_flag[n] = CORNER;
						++n;
					}
					else if((geometry[i+1][j][k] == OPEN)
						&& (geometry[i-1][j][k] == SOLID)
						&& (geometry[i][j+1][k] == OPEN)
						&& (geometry[i][j-1][k] == SOLID)
						&& (geometry[i][j][k+1] == SOLID)
						&& (geometry[i][j][k-1] == OPEN)) {
						x_boundary[n] = i;
						y_boundary[n] = j;
						z_boundary[n] = k;
						boundary_flag[n] = CORNER;
						++n;
					}
					else if((geometry[i+1][j][k] == SOLID)
						&& (geometry[i-1][j][k] == OPEN)
						&& (geometry[i][j+1][k] == OPEN)
						&& (geometry[i][j-1][k] == SOLID)
						&& (geometry[i][j][k+1] == SOLID)
						&& (geometry[i][j][k-1] == OPEN)) {
						x_boundary[n] = i;
						y_boundary[n] = j;
						z_boundary[n] = k;
						boundary_flag[n] = CORNER;
						++n;
					}
				}
			}
		}
	}
/*
	for(k = 0; k < n; k++) {
		if(boundary_flag[k] == CORNER) 
			geometry[x_boundary[k]][y_boundary[k]][z_boundary[k]] = OPEN; 
	}
*/

	return(n);
}
					
/*
 *	display the classification of the boundary points on the recorder
 *					
 *	1 indicates a surface parallel to x with the air above    == XUP
 *	2 indicates a surface parallel to x with the air below    == XDOWN
 *	3 indicates a surface parallel to y with the air on right == YUP
 *	4 indicates a surface parallel to y with the air on left  == YDOWN
 *	5 indicates a surface parallel to y with the air on right == ZUP
 *	6 indicates a surface parallel to y with the air on left  == ZDOWN
 *	7 indicates a convex corner                               == CORNER
 */

int
display_boundary()
{
	int i,j,k,m,flag;
	FILE *fp1,*fp2,*fp3,*fp4,*fp5,*fp6,*fp7;
	char mes[400];

	fp1 = fopen("b_case_1","w");
	fp2 = fopen("b_case_2","w");
	fp3 = fopen("b_case_3","w");
	fp4 = fopen("b_case_4","w");
	fp5 = fopen("b_case_5","w");
	fp6 = fopen("b_case_6","w");
	fp7 = fopen("b_case_7","w");

	for(m = 0; m < n_boundary; m++) {
		i = x_boundary[m];	
		j = y_boundary[m];	
		k = z_boundary[m];
		flag = boundary_flag[m];
		if(flag == XUP) fprintf(fp1,"%d\t%d\t%d\n",i,j,k);			
		if(flag == XDOWN) fprintf(fp2,"%d\t%d\t%d\n",i,j,k);			
		if(flag == YUP) fprintf(fp3,"%d\t%d\t%d\n",i,j,k);			
		if(flag == YDOWN) fprintf(fp4,"%d\t%d\t%d\n",i,j,k);			
		if(flag == ZUP) fprintf(fp5,"%d\t%d\t%d\n",i,j,k);			
		if(flag == ZDOWN) fprintf(fp6,"%d\t%d\t%d\n",i,j,k);			
		if(flag == CORNER) fprintf(fp7,"%d\t%d\t%d\n",i,j,k);			
	}

	fclose(fp1);
	fclose(fp2);
	fclose(fp3);
	fclose(fp4);
	fclose(fp5);
	fclose(fp6);
	fclose(fp7);

	return(0);
}

/* 
 *	save data for a restart if desired
 *	
 *	put restart time in file t_restart
 *	put rho, u, v, and w data into one file "restart_maps.dat" using
 *	a format similar to the one used for saving maps above
 *	all in the results directory
 *
 *	the map data is stored in the format
 *	i	j	k	rho	u	v	w
 *	.	.	.
 *
 *	this is changed significantly from 2D version
 *	now put all map info into one file
 */
int
save_for_restart()
{
	int i,j,k;
	FILE *fp_map_restart;
	FILE *fp_t_restart;
	FILE *fp_lip_restart;
	char tmp[300],tmp2[300],mes[400];
	static int first_time = YES;

	sprintf(tmp,"%s/%s.restart_maps.dat",scratch_directory,results_directory);

// before saving the latest maps, back up the previous restart info, just in case 
// the program stops in the middle of saving this stuff
// make some small changes here (10-28-12) to have better safety
	if(first_time == NO) {
		sprintf(tmp2,"%s/%s.backup_restart_maps",scratch_directory,results_directory);
		sprintf(mes,"cp %s %s\n",tmp,tmp2); 
		system(mes);
	}

	fp_map_restart = fopen(tmp,"w");

	sprintf(tmp,"%s/t_restart",results_directory_full_path);

// also save the the previous restart time
	if(first_time == NO) {
		sprintf(tmp2,"%s/backup_t_restart.dat",results_directory_full_path);
		sprintf(mes,"cp %s %s\n",tmp,tmp2); 
		system(mes);
	}

	fp_t_restart = fopen(tmp,"w");

	fprintf(fp_t_restart,"%g\n",t);
	for(i = 0; i <= i_max; i++) {
		for(j = 0; j <= j_max; j++) {
			for(k = 0; k <= k_max; k++) {
				fprintf(fp_map_restart,"%d\t%d\t%d\t%g\t%g\t%g\t%g\n",i,j,k,
					rho[i][j][k],u[i][j][k],v[i][j][k],w[i][j][k]);
			}
		}
	}

	fclose(fp_t_restart);
	fclose(fp_map_restart);

// now deal with lip variables

	sprintf(tmp,"%s/%s.lip_restart.dat",scratch_directory,results_directory);

	if(first_time == NO) {
		sprintf(tmp2,"%s/%s.backup_lip_restart.dat",scratch_directory,results_directory);
		sprintf(mes,"cp %s %s\n",tmp,tmp2); 
		system(mes);
	}

	fp_lip_restart = fopen(tmp,"w");

	fprintf(fp_lip_restart,"%d\t%d\n%d\t%d\n%d\t%d\n",i_lip_region_min,i_lip_region_max,
		j_lip_region_min,j_lip_region_max,k_lip_region_min,k_lip_region_max);
	fprintf(fp_lip_restart,"%g\t%g\n",i_width[LEFT],j_width[LEFT]);
//	fprintf(fp_lip_restart,"%g\t%g\t%g\t%g\n",i_center[LEFT][CURRENT],i_center[LEFT][OLD],
//		di_center[LEFT][CURRENT],di_center[LEFT][OLD]);
	fprintf(fp_lip_restart,"%g\t%g\t%g\t%g\t%g\t%g\n",i_center[LEFT][CURRENT],i_center[LEFT][OLD],
		di_center[LEFT][CURRENT],di_center[LEFT][OLD],
		di_center_interior[LEFT][CURRENT],di_center_interior[LEFT][OLD]);
	fprintf(fp_lip_restart,"%g\t%g\t%g\t%g\t%g\t%g\n",j_center[LEFT][CURRENT],j_center[LEFT][OLD],
		dj_center[LEFT][CURRENT],dj_center[LEFT][OLD],
		dj_center_interior[LEFT][CURRENT],dj_center_interior[LEFT][OLD]);
	fprintf(fp_lip_restart,"%d\t%d\n",i_corner[LEFT],j_corner[LEFT]);

	fprintf(fp_lip_restart,"%g\t%g\n",i_width[RIGHT],j_width[RIGHT]);
//	fprintf(fp_lip_restart,"%g\t%g\t%g\t%g\n",i_center[RIGHT][CURRENT],i_center[RIGHT][OLD],
//		di_center[RIGHT][CURRENT],di_center[RIGHT][OLD]);
	fprintf(fp_lip_restart,"%g\t%g\t%g\t%g\t%g\t%g\n",i_center[RIGHT][CURRENT],i_center[RIGHT][OLD],
		di_center[RIGHT][CURRENT],di_center[RIGHT][OLD],
		di_center_interior[RIGHT][CURRENT],di_center_interior[RIGHT][OLD]);
	fprintf(fp_lip_restart,"%g\t%g\t%g\t%g\t%g\t%g\n",j_center[RIGHT][CURRENT],j_center[RIGHT][OLD],
		dj_center[RIGHT][CURRENT],dj_center[RIGHT][OLD],
		dj_center_interior[RIGHT][CURRENT],dj_center_interior[RIGHT][OLD]);
	fprintf(fp_lip_restart,"%d\t%d\n",i_corner[RIGHT],j_corner[RIGHT]);

	fclose(fp_lip_restart);

	first_time = NO;

	return(0);
}

/*
 * 	the velocity imposed in the channel is time dependent
 *	in this version it starts at 0 at t = 0, increases linearly
 *	up to a time t_blow_transient at which time it has the value u_init
 *
 *	it stays at u_init until t = t_stop_blowing after which it ramps down to
 *	zero in a time t_ramp_down and then stays at zero thereafter
 */
double blowing_velocity(t_current,i,j,k)
double t_current;
int i,j,k;
{
	double val;

	if(geometry[i][j][k] != INIT_POINT) {
		fprintf(fp_log,"error A initializing u and rho -- i,j,k (%d %d %d) not in init region\n",i,j,k);
		exit(0);
	}
	if(t_current <= t_blow_transient) {
		val = u_init * init_val_j[j] * init_val_k[k] * t_current / t_blow_transient;
	}
	else if((t_current > t_stop_blowing) && 
			(t_current <= t_stop_blowing+t_ramp_down)) {
		val = u_init * init_val_j[j] * init_val_k[k] * (1.0 - (t_current-t_stop_blowing)/t_ramp_down); 
	}
	else if(t_current > t_stop_blowing+t_ramp_down) {
		val = 0.0;
	}
	else {
		val = u_init * init_val_j[j] * init_val_k[k];
	}

	return(val);
}

double
artificial_viscosity(int i,int j,int k,float ***q,float ***r,double v1_0,double v2_0)
{
	double val;
	double e2x_plus,e4x_plus;
	double e2x_minus,e4x_minus;
	double e2x,e2y,e2z;
	double e2y_plus,e4y_plus;
	double e2y_minus,e4y_minus;
	double e2z_plus,e4z_plus;
	double e2z_minus,e4z_minus;
	double nux_plus,nux,nux_minus;
	double nuy_plus,nuy,nuy_minus;
	double nuz_plus,nuz,nuz_minus;
	double v1,v2;

	v1 = v1_0;
	v2 = v2_0;

	if((geometry[i+1][j][k] == OPEN) && (geometry[i-1][j][k] == OPEN) 
		&& (geometry[i][j+1][k] == OPEN) && (geometry[i][j-1][k] == OPEN)
		&& (geometry[i][j][k+1] == OPEN) && (geometry[i][j][k-1] == OPEN)) {

		nux_plus =  fabs(r[i+2][j][k]-2.0*r[i+1][j][k]+r[i][j][k])/(4.0*rho_air);
		nux =       fabs(r[i+1][j][k]-2.0*r[i][j][k]+r[i-1][j][k])/(4.0*rho_air);
		nux_minus = fabs(r[i][j][k]-2.0*r[i-1][j][k]+r[i-2][j][k])/(4.0*rho_air);
		e2x_plus =  v1 * bigger(nux_plus,nux);
		e2x_minus = v1 * bigger(nux_minus,nux);

		nuy_plus =  fabs(r[i][j+2][k]-2.0*r[i][j+1][k]+r[i][j][k])/(4.0*rho_air);
		nuy =       fabs(r[i][j+1][k]-2.0*r[i][j][k]+r[i][j-1][k])/(4.0*rho_air);
		nuy_minus = fabs(r[i][j][k]-2.0*r[i][j-1][k]+r[i][j-2][k])/(4.0*rho_air);
		e2y_plus =  v1 * bigger(nuy_plus,nuy);
		e2y_minus = v1 * bigger(nuy_minus,nuy);

		nuz_plus =  fabs(r[i][j][k+2]-2.0*r[i][j][k+1]+r[i][j][k])/(4.0*rho_air);
		nuz =       fabs(r[i][j][k+1]-2.0*r[i][j][k]+r[i][j][k-1])/(4.0*rho_air);
		nuz_minus = fabs(r[i][j][k]-2.0*r[i][j][k-1]+r[i][j][k-2])/(4.0*rho_air);
		e2z_plus =  v1 * bigger(nuz_plus,nuz);
		e2z_minus = v1 * bigger(nuz_minus,nuz);

		val = e2x_plus*(q[i+1][j][k] - q[i][j][k]) - e2x_minus*(q[i][j][k] - q[i-1][j][k])
	    	+ e2y_plus*(q[i][j+1][k] - q[i][j][k]) - e2y_minus*(q[i][j][k] - q[i][j-1][k]);
	    	+ e2z_plus*(q[i][j][k+1] - q[i][j][k]) - e2z_minus*(q[i][j][k] - q[i][j][k-1]);

		e4x_plus =  bigger(0.0,v2 - e2x_plus);
		e4x_minus = bigger(0.0,v2 - e2x_minus);
		e4y_plus =  bigger(0.0,v2 - e2y_plus);
		e4y_minus = bigger(0.0,v2 - e2y_minus);
		e4z_plus =  bigger(0.0,v2 - e2z_plus);
		e4z_minus = bigger(0.0,v2 - e2z_minus);

		val -= e4x_plus * (q[i+2][j][k]-3.0*q[i+1][j][k]+3.0*q[i][j][k]-q[i-1][j][k])
	     	- e4x_minus *(q[i+1][j][k]-3.0*q[i][j][k]+3.0*q[i-1][j][k]-q[i-2][j][k])
	     	+ e4y_plus * (q[i][j+2][k]-3.0*q[i][j+1][k]+3.0*q[i][j][k]-q[i][j-1][k])
	     	- e4y_minus *(q[i][j+1][k]-3.0*q[i][j][k]+3.0*q[i][j-1][k]-q[i][j-2][k])
	     	+ e4z_plus * (q[i][j][k+2]-3.0*q[i][j][k+1]+3.0*q[i][j][k]-q[i][j][k-1])
	     	- e4z_minus *(q[i][j][k+1]-3.0*q[i][j][k]+3.0*q[i][j][k-1]-q[i][j][k-2]);
	}
	else if((geometry[i+1][j][k] != OPEN) && (geometry[i-1][j][k] == OPEN) 
		&& (geometry[i][j+1][k] == OPEN) && (geometry[i][j-1][k] == OPEN)
		&& (geometry[i][j][k+1] == OPEN) && (geometry[i][j][k-1] == OPEN)) {

                nux =       fabs(r[i+1][j][k]-2.0*r[i][j][k]+r[i-1][j][k])/(4.0*rho_air);
                nux_minus = fabs(r[i][j][k]-2.0*r[i-1][j][k]+r[i-2][j][k])/(4.0*rho_air);
                e2x_plus =  v1 * nux;
                e2x_minus = v1 * bigger(nux_minus,nux);

                nuy_plus =  fabs(r[i][j+2][k]-2.0*r[i][j+1][k]+r[i][j][k])/(4.0*rho_air);
                nuy =       fabs(r[i][j+1][k]-2.0*r[i][j][k]+r[i][j-1][k])/(4.0*rho_air);
                nuy_minus = fabs(r[i][j][k]-2.0*r[i][j-1][k]+r[i][j-2][k])/(4.0*rho_air);
                e2y_plus =  v1 * bigger(nuy_plus,nuy);
                e2y_minus = v1 * bigger(nuy_minus,nuy);

		nuz_plus =  fabs(r[i][j][k+2]-2.0*r[i][j][k+1]+r[i][j][k])/(4.0*rho_air);
		nuz =       fabs(r[i][j][k+1]-2.0*r[i][j][k]+r[i][j][k-1])/(4.0*rho_air);
		nuz_minus = fabs(r[i][j][k]-2.0*r[i][j][k-1]+r[i][j][k-2])/(4.0*rho_air);
		e2z_plus =  v1 * bigger(nuz_plus,nuz);
		e2z_minus = v1 * bigger(nuz_minus,nuz);

                val = e2x_plus*(q[i+1][j][k] - q[i][j][k]) - e2x_minus*(q[i][j][k] - q[i-1][j][k])
                    + e2y_plus*(q[i][j+1][k] - q[i][j][k]) - e2y_minus*(q[i][j][k] - q[i][j-1][k])
                    + e2z_plus*(q[i][j][k+1] - q[i][j][k]) - e2z_minus*(q[i][j][k] - q[i][j][k-1]);

                e4x_plus =  bigger(0.0,v2 - e2x_plus);
                e4x_minus = bigger(0.0,v2 - e2x_minus);
                e4y_plus =  bigger(0.0,v2 - e2y_plus);
                e4y_minus = bigger(0.0,v2 - e2y_minus);
                e4z_plus =  bigger(0.0,v2 - e2z_plus);
                e4z_minus = bigger(0.0,v2 - e2z_minus);

// I am not sure about the leading "(" in the next line
                val -= -(e4x_plus * (q[i+1][j][k]-3.0*q[i][j][k]+3.0*q[i-1][j][k]-q[i-2][j][k])
                     - e4x_minus *(q[i][j][k]-3.0*q[i-1][j][k]+3.0*q[i-2][j][k]-q[i-3][j][k]))
                     + e4y_plus * (q[i][j+2][k]-3.0*q[i][j+1][k]+3.0*q[i][j][k]-q[i][j-1][k])
                     - e4y_minus *(q[i][j+1][k]-3.0*q[i][j][k]+3.0*q[i][j-1][k]-q[i][j-2][k])
                     + e4z_plus * (q[i][j][k+2]-3.0*q[i][j][k+1]+3.0*q[i][j][k]-q[i][j][k-1])
                     - e4z_minus *(q[i][j][k+1]-3.0*q[i][j][k]+3.0*q[i][j][k-1]-q[i][j][k-2]);
        }
	else if((geometry[i+1][j][k] == OPEN) && (geometry[i-1][j][k] != OPEN) 
		&& (geometry[i][j+1][k] == OPEN) && (geometry[i][j-1][k] == OPEN)
		&& (geometry[i][j][k+1] == OPEN) && (geometry[i][j][k-1] == OPEN)) {

		nux_plus =  fabs(r[i+2][j][k]-2.0*r[i+1][j][k]+r[i][j][k])/(4.0*rho_air);
		nux =       fabs(r[i+1][j][k]-2.0*r[i][j][k]+r[i-1][j][k])/(4.0*rho_air);
		e2x_plus =  v1 * bigger(nux_plus,nux);
		e2x_minus = v1 * nux;

		nuy_plus =  fabs(r[i][j+2][k]-2.0*r[i][j+1][k]+r[i][j][k])/(4.0*rho_air);
		nuy =       fabs(r[i][j+1][k]-2.0*r[i][j][k]+r[i][j-1][k])/(4.0*rho_air);
		nuy_minus = fabs(r[i][j][k]-2.0*r[i][j-1][k]+r[i][j-2][k])/(4.0*rho_air);
		e2y_plus =  v1 * bigger(nuy_plus,nuy);
		e2y_minus = v1 * bigger(nuy_minus,nuy);

		nuz_plus =  fabs(r[i][j][k+2]-2.0*r[i][j][k+1]+r[i][j][k])/(4.0*rho_air);
		nuz =       fabs(r[i][j][k+1]-2.0*r[i][j][k]+r[i][j][k-1])/(4.0*rho_air);
		nuz_minus = fabs(r[i][j][k]-2.0*r[i][j][k-1]+r[i][j][k-2])/(4.0*rho_air);
		e2z_plus =  v1 * bigger(nuz_plus,nuz);
		e2z_minus = v1 * bigger(nuz_minus,nuz);

		val = e2x_plus*(q[i+1][j][k] - q[i][j][k]) - e2x_minus*(q[i][j][k] - q[i-1][j][k])
		    + e2y_plus*(q[i][j+1][k] - q[i][j][k]) - e2y_minus*(q[i][j][k] - q[i][j-1][k])
		    + e2z_plus*(q[i][j][k+1] - q[i][j][k]) - e2z_minus*(q[i][j][k] - q[i][j][k-1]);

		e4x_plus =  bigger(0.0,v2 - e2x_plus);
		e4x_minus = bigger(0.0,v2 - e2x_minus);
		e4y_plus =  bigger(0.0,v2 - e2y_plus);
		e4y_minus = bigger(0.0,v2 - e2y_minus);
		e4z_plus =  bigger(0.0,v2 - e2z_plus);
		e4z_minus = bigger(0.0,v2 - e2z_minus);

// I am not sure about the leading "(" in the next line
		val -= -(e4x_plus * (q[i+3][j][k]-3.0*q[i+2][j][k]+3.0*q[i+1][j][k]-q[i][j][k])
		     - e4x_minus *(q[i+2][j][k]-3.0*q[i+1][j][k]+3.0*q[i][j][k]-q[i-1][j][k]))
		     + e4y_plus * (q[i][j+2][k]-3.0*q[i][j+1][k]+3.0*q[i][j][k]-q[i][j-1][k])
		     - e4y_minus *(q[i][j+1][k]-3.0*q[i][j][k]+3.0*q[i][j-1][k]-q[i][j-2][k])
		     + e4z_plus * (q[i][j][k+2]-3.0*q[i][j][k+1]+3.0*q[i][j][k]-q[i][j][k-1])
		     - e4z_minus *(q[i][j][k+1]-3.0*q[i][j][k]+3.0*q[i][j][k-1]-q[i][j][k-2]);
	}
	else if((geometry[i+1][j][k] == OPEN) && (geometry[i-1][j][k] == OPEN) 
		&& (geometry[i][j+1][k] != OPEN) && (geometry[i][j-1][k] == OPEN)
		&& (geometry[i][j][k+1] == OPEN) && (geometry[i][j][k-1] == OPEN)) {

		nux_plus =  fabs(r[i+2][j][k]-2.0*r[i+1][j][k]+r[i][j][k])/(4.0*rho_air);
		nux =       fabs(r[i+1][j][k]-2.0*r[i][j][k]+r[i-1][j][k])/(4.0*rho_air);
		nux_minus = fabs(r[i][j][k]-2.0*r[i-1][j][k]+r[i-2][j][k])/(4.0*rho_air);
		e2x_plus =  v1 * bigger(nux_plus,nux);
		e2x_minus = v1 * bigger(nux_minus,nux);

		nuy =       fabs(r[i][j+1][k]-2.0*r[i][j][k]+r[i][j-1][k])/(4.0*rho_air);
		nuy_minus = fabs(r[i][j][k]-2.0*r[i][j-1][k]+r[i][j-2][k])/(4.0*rho_air);
		e2y_plus =  v1 * nuy;
		e2y_minus = v1 * bigger(nuy_minus,nuy);

		nuz_plus =  fabs(r[i][j][k+2]-2.0*r[i][j][k+1]+r[i][j][k])/(4.0*rho_air);
		nuz =       fabs(r[i][j][k+1]-2.0*r[i][j][k]+r[i][j][k-1])/(4.0*rho_air);
		nuz_minus = fabs(r[i][j][k]-2.0*r[i][j][k-1]+r[i][j][k-2])/(4.0*rho_air);
		e2z_plus =  v1 * bigger(nuz_plus,nuz);
		e2z_minus = v1 * bigger(nuz_minus,nuz);

		val = e2x_plus*(q[i+1][j][k] - q[i][j][k]) - e2x_minus*(q[i][j][k] - q[i-1][j][k])
		    + e2y_plus*(q[i][j+1][k] - q[i][j][k]) - e2y_minus*(q[i][j][k] - q[i][j-1][k])
		    + e2z_plus*(q[i][j][k+1] - q[i][j][k]) - e2z_minus*(q[i][j][k] - q[i][j][k-1]);

		e4x_plus =  bigger(0.0,v2 - e2x_plus);
		e4x_minus = bigger(0.0,v2 - e2x_minus);
		e4y_plus =  bigger(0.0,v2 - e2y_plus);
		e4y_minus = bigger(0.0,v2 - e2y_minus);
		e4z_plus =  bigger(0.0,v2 - e2z_plus);
		e4z_minus = bigger(0.0,v2 - e2z_minus);

// I am not sure about the leading "(" in the third line below
		val -= e4x_plus * (q[i+2][j][k]-3.0*q[i+1][j][k]+3.0*q[i][j][k]-q[i-1][j][k])
		     - e4x_minus *(q[i+1][j][k]-3.0*q[i][j][k]+3.0*q[i-1][j][k]-q[i-2][j][k])
		     -(e4y_plus * (q[i][j+1][k]-3.0*q[i][j][k]+3.0*q[i][j-1][k]-q[i][j-2][k])
		     - e4y_minus *(q[i][j][k]-3.0*q[i][j-1][k]+3.0*q[i][j-2][k]-q[i][j-3][k]))
		     + e4z_plus * (q[i][j][k+2]-3.0*q[i][j][k+1]+3.0*q[i][j][k]-q[i][j][k-1])
		     - e4z_minus *(q[i][j][k+1]-3.0*q[i][j][k]+3.0*q[i][j][k-1]-q[i][j][k-2]);
	}
	else if((geometry[i+1][j][k] == OPEN) && (geometry[i-1][j][k] == OPEN) 
		&& (geometry[i][j+1][k] == OPEN) && (geometry[i][j-1][k] != OPEN)
		&& (geometry[i][j][k+1] == OPEN) && (geometry[i][j][k-1] == OPEN)) {

		nux_plus =  fabs(r[i+2][j][k]-2.0*r[i+1][j][k]+r[i][j][k])/(4.0*rho_air);
		nux =       fabs(r[i+1][j][k]-2.0*r[i][j][k]+r[i-1][j][k])/(4.0*rho_air);
		nux_minus = fabs(r[i][j][k]-2.0*r[i-1][j][k]+r[i-2][j][k])/(4.0*rho_air);
		e2x_plus =  v1 * bigger(nux_plus,nux);
		e2x_minus = v1 * bigger(nux_minus,nux);

		nuy_plus =  fabs(r[i][j+2][k]-2.0*r[i][j+1][k]+r[i][j][k])/(4.0*rho_air);
		nuy =       fabs(r[i][j+1][k]-2.0*r[i][j][k]+r[i][j-1][k])/(4.0*rho_air);
		e2y_plus =  v1 * bigger(nuy_plus,nuy);
		e2y_minus = v1 * nuy;

		nuz_plus =  fabs(r[i][j][k+2]-2.0*r[i][j][k+1]+r[i][j][k])/(4.0*rho_air);
		nuz =       fabs(r[i][j][k+1]-2.0*r[i][j][k]+r[i][j][k-1])/(4.0*rho_air);
		nuz_minus = fabs(r[i][j][k]-2.0*r[i][j][k-1]+r[i][j][k-2])/(4.0*rho_air);
		e2z_plus =  v1 * bigger(nuz_plus,nuz);
		e2z_minus = v1 * bigger(nuz_minus,nuz);

		val = e2x_plus*(q[i+1][j][k] - q[i][j][k]) - e2x_minus*(q[i][j][k] - q[i-1][j][k])
		    + e2y_plus*(q[i][j+1][k] - q[i][j][k]) - e2y_minus*(q[i][j][k] - q[i][j-1][k])
		    + e2z_plus*(q[i][j][k+1] - q[i][j][k]) - e2z_minus*(q[i][j][k] - q[i][j][k-1]);

		e4x_plus =  bigger(0.0,v2 - e2x_plus);
		e4x_minus = bigger(0.0,v2 - e2x_minus);
		e4y_plus =  bigger(0.0,v2 - e2y_plus);
		e4y_minus = bigger(0.0,v2 - e2y_minus);
		e4z_plus =  bigger(0.0,v2 - e2z_plus);
		e4z_minus = bigger(0.0,v2 - e2z_minus);

// I am not sure about the leading "(" in the third line below
		val -= e4x_plus * (q[i+2][j][k]-3.0*q[i+1][j][k]+3.0*q[i][j][k]-q[i-1][j][k])
		     - e4x_minus *(q[i+1][j][k]-3.0*q[i][j][k]+3.0*q[i-1][j][k]-q[i-2][j][k])
		     -(e4y_plus * (q[i][j+3][k]-3.0*q[i][j+2][k]+3.0*q[i][j+1][k]-q[i][j][k])
		     - e4y_minus *(q[i][j+2][k]-3.0*q[i][j+1][k]+3.0*q[i][j][k]-q[i][j-1][k]))
		     + e4z_plus * (q[i][j][k+2]-3.0*q[i][j][k+1]+3.0*q[i][j][k]-q[i][j][k-1])
		     - e4z_minus *(q[i][j][k+1]-3.0*q[i][j][k]+3.0*q[i][j][k-1]-q[i][j][k-2]);
	}
	else if((geometry[i+1][j][k] == OPEN) && (geometry[i-1][j][k] == OPEN) 
		&& (geometry[i][j+1][k] == OPEN) && (geometry[i][j-1][k] == OPEN)
		&& (geometry[i][j][k+1] != OPEN) && (geometry[i][j][k-1] == OPEN)) {

		nux_plus =  fabs(r[i+2][j][k]-2.0*r[i+1][j][k]+r[i][j][k])/(4.0*rho_air);
		nux =       fabs(r[i+1][j][k]-2.0*r[i][j][k]+r[i-1][j][k])/(4.0*rho_air);
		nux_minus = fabs(r[i][j][k]-2.0*r[i-1][j][k]+r[i-2][j][k])/(4.0*rho_air);
		e2x_plus =  v1 * bigger(nux_plus,nux);
		e2x_minus = v1 * bigger(nux_minus,nux);

		nuy_plus =  fabs(r[i][j+2][k]-2.0*r[i][j+1][k]+r[i][j][k])/(4.0*rho_air);
		nuy =       fabs(r[i][j+1][k]-2.0*r[i][j][k]+r[i][j-1][k])/(4.0*rho_air);
		nuy_minus = fabs(r[i][j][k]-2.0*r[i][j-1][k]+r[i][j-2][k])/(4.0*rho_air);
		e2y_plus =  v1 * bigger(nuy_plus,nuy);
		e2y_minus = v1 * bigger(nuy_minus,nuy);

		nuz =       fabs(r[i][j][k+1]-2.0*r[i][j][k]+r[i][j][k-1])/(4.0*rho_air);
		nuz_minus = fabs(r[i][j][k]-2.0*r[i][j][k-1]+r[i][j][k-2])/(4.0*rho_air);
		e2z_plus =  v1 * nuz;
		e2z_minus = v1 * bigger(nuz_minus,nuz);

		val = e2x_plus*(q[i+1][j][k] - q[i][j][k]) - e2x_minus*(q[i][j][k] - q[i-1][j][k])
		    + e2y_plus*(q[i][j+1][k] - q[i][j][k]) - e2y_minus*(q[i][j][k] - q[i][j-1][k])
		    + e2z_plus*(q[i][j][k+1] - q[i][j][k]) - e2z_minus*(q[i][j][k] - q[i][j][k-1]);

		e4x_plus =  bigger(0.0,v2 - e2x_plus);
		e4x_minus = bigger(0.0,v2 - e2x_minus);
		e4y_plus =  bigger(0.0,v2 - e2y_plus);
		e4y_minus = bigger(0.0,v2 - e2y_minus);
		e4z_plus =  bigger(0.0,v2 - e2z_plus);
		e4z_minus = bigger(0.0,v2 - e2z_minus);

// I am not sure about the leading "(" in the fifth line below
		val -= e4x_plus * (q[i+2][j][k]-3.0*q[i+1][j][k]+3.0*q[i][j][k]-q[i-1][j][k])
		     - e4x_minus *(q[i+1][j][k]-3.0*q[i][j][k]+3.0*q[i-1][j][k]-q[i-2][j][k])
		     + e4y_plus * (q[i][j+2][k]-3.0*q[i][j+1][k]+3.0*q[i][j][k]-q[i][j-1][k])
		     - e4y_minus *(q[i][j+1][k]-3.0*q[i][j][k]+3.0*q[i][j-1][k]-q[i][j-2][k])
		     -(e4z_plus * (q[i][j][k+1]-3.0*q[i][j][k]+3.0*q[i][j][k-1]-q[i][j][k-2])
		     - e4z_minus *(q[i][j][k]-3.0*q[i][j][k-1]+3.0*q[i][j][k-2]-q[i][j][k-3]));
	}
	else if((geometry[i+1][j][k] == OPEN) && (geometry[i-1][j][k] == OPEN) 
		&& (geometry[i][j+1][k] == OPEN) && (geometry[i][j-1][k] == OPEN)
		&& (geometry[i][j][k+1] == OPEN) && (geometry[i][j][k-1] != OPEN)) {

		nux_plus =  fabs(r[i+2][j][k]-2.0*r[i+1][j][k]+r[i][j][k])/(4.0*rho_air);
		nux =       fabs(r[i+1][j][k]-2.0*r[i][j][k]+r[i-1][j][k])/(4.0*rho_air);
		nux_minus = fabs(r[i][j][k]-2.0*r[i-1][j][k]+r[i-2][j][k])/(4.0*rho_air);
		e2x_plus =  v1 * bigger(nux_plus,nux);
		e2x_minus = v1 * bigger(nux_minus,nux);

		nuy_plus =  fabs(r[i][j+2][k]-2.0*r[i][j+1][k]+r[i][j][k])/(4.0*rho_air);
		nuy =       fabs(r[i][j+1][k]-2.0*r[i][j][k]+r[i][j-1][k])/(4.0*rho_air);
		nuy_minus = fabs(r[i][j][k]-2.0*r[i][j-1][k]+r[i][j-2][k])/(4.0*rho_air);
		e2y_plus =  v1 * bigger(nuy_plus,nuy);
		e2y_minus = v1 * bigger(nuy_minus,nuy);

		nuz_plus =  fabs(r[i][j][k+2]-2.0*r[i][j][k+1]+r[i][j][k])/(4.0*rho_air);
		nuz =       fabs(r[i][j][k+1]-2.0*r[i][j][k]+r[i][j][k-1])/(4.0*rho_air);
		e2z_plus =  v1 * bigger(nuz_plus,nuz);
		e2z_minus = v1 * nuz;

		val = e2x_plus*(q[i+1][j][k] - q[i][j][k]) - e2x_minus*(q[i][j][k] - q[i-1][j][k])
		    + e2y_plus*(q[i][j+1][k] - q[i][j][k]) - e2y_minus*(q[i][j][k] - q[i][j-1][k])
		    + e2z_plus*(q[i][j][k+1] - q[i][j][k]) - e2z_minus*(q[i][j][k] - q[i][j][k-1]);

		e4x_plus =  bigger(0.0,v2 - e2x_plus);
		e4x_minus = bigger(0.0,v2 - e2x_minus);
		e4y_plus =  bigger(0.0,v2 - e2y_plus);
		e4y_minus = bigger(0.0,v2 - e2y_minus);
		e4z_plus =  bigger(0.0,v2 - e2z_plus);
		e4z_minus = bigger(0.0,v2 - e2z_minus);

// I am not sure about the leading "(" in the fifth line below
		val -= e4x_plus * (q[i+2][j][k]-3.0*q[i+1][j][k]+3.0*q[i][j][k]-q[i-1][j][k])
		     - e4x_minus *(q[i+1][j][k]-3.0*q[i][j][k]+3.0*q[i-1][j][k]-q[i-2][j][k])
		     + e4y_plus * (q[i][j+2][k]-3.0*q[i][j+1][k]+3.0*q[i][j][k]-q[i][j-1][k])
		     - e4y_minus *(q[i][j+1][k]-3.0*q[i][j][k]+3.0*q[i][j-1][k]-q[i][j-2][k])
		     -(e4z_plus * (q[i][j][k+3]-3.0*q[i][j][k+2]+3.0*q[i][j][k+1]-q[i][j][k])
		     - e4z_minus *(q[i][j][k+2]-3.0*q[i][j][k+1]+3.0*q[i][j][k]-q[i][j][k-1]));
	}
	else {
		e2x = v1 * fabs(r[i+1][j][k]-2.0*r[i][j][k]+r[i-1][j][k])/(4.0*rho_air);
	
		e2y = v1 * fabs(r[i][j+1][k]-2.0*r[i][j][k]+r[i][j-1][k])/(4.0*rho_air);

		e2z = v1 * fabs(r[i][j][k+1]-2.0*r[i][j][k]+r[i][j][k-1])/(4.0*rho_air);

		val = e2x * (q[i+1][j][k]-2.0*q[i][j][k]+q[i-1][j][k])
		    + e2y * (q[i][j+1][k]-2.0*q[i][j][k]+q[i][j-1][k])
		    + e2z * (q[i][j][k+1]-2.0*q[i][j][k]+q[i][j][k-1]);
	}

	return(val);
}

double
bigger(double x1,double x2)
{
	if(x1 >= x2) {
		return(x1);
	}
	else {
		return(x2);
	}
}

/*
 *      this is only used for dealing with rho
 *      on the surface of the recorder
 *
 *      n = index of boundary[] that describes this point
 *      v1 and v2 are the viscosity coefficients for the recorder surface
 *
 *	IMPORTANT NOTE: the convention for XUP, XDOWN, etc. is different from in previous
 *		versions, so these equations will look a bit different from in recorder7c.c
 */
double
artificial_viscosity_on_recorder(int n,int i,int j,int k,double v1_0,double v2_0)
{
        double val;
        double e2x_plus,e4x_plus;
        double e2x_minus,e4x_minus;
        double e2x,e2y,e2z;
        double e2y_plus,e4y_plus;
        double e2y_minus,e4y_minus;
        double e2z_plus,e4z_plus;
        double e2z_minus,e4z_minus;
        double nux_plus,nux,nux_minus;
        double nuy_plus,nuy,nuy_minus;
        double nuz_plus,nuz,nuz_minus;
	double v1,v2;

	return(0.0);

	v1 = 0.0; // 0.03 * v1_0;
	v2 = 0.0; // 0.03 * v2_0;

        if(boundary_flag[n] == XUP) {

                nux_plus =  fabs(rho[i+2][j][k]-2.0*rho[i+1][j][k]+rho[i][j][k])/(4.0*rho_air);
                e2x_plus =  v1 * nux_plus;
                e2x_minus = e2x_plus;

                nuy_plus =  fabs(rho[i][j+2][k]-2.0*rho[i][j+1][k]+rho[i][j][k])/(4.0*rho_air);
// found a mistake on the next line in recorder7c.c !! (fixed here)
                nuy      =  fabs(rho[i][j+1][k]-2.0*rho[i][j][k]+rho[i][j-1][k])/(4.0*rho_air);
                nuy_minus =  fabs(rho[i][j][k]-2.0*rho[i][j-1][k]+rho[i][j-2][k])/(4.0*rho_air);
                e2y_plus =  v1 * bigger(nuy_plus,nuy);
                e2y_minus = v1 * bigger(nuy_minus,nuy);

                nuz_plus =  fabs(rho[i][j][k+2]-2.0*rho[i][j][k+1]+rho[i][j][k])/(4.0*rho_air);
// found a mistake on the next line in recorder7c.c !! (fixed here)
                nuz      =  fabs(rho[i][j][k+1]-2.0*rho[i][j][k]+rho[i][j][k-1])/(4.0*rho_air);
                nuz_minus =  fabs(rho[i][j][k]-2.0*rho[i][j][k-1]+rho[i][j][k-2])/(4.0*rho_air);
                e2z_plus =  v1 * bigger(nuz_plus,nuz);
                e2z_minus = v1 * bigger(nuz_minus,nuz);

                val = e2x_plus*(rho[i+2][j][k] - rho[i+1][j][k]) - e2x_minus*(rho[i+1][j][k] - rho[i][j][k])
                    + e2y_plus*(rho[i][j+1][k] - rho[i][j][k]) - e2y_minus*(rho[i][j][k] - rho[i][j-1][k])
                    + e2z_plus*(rho[i][j][k+1] - rho[i][j][k]) - e2z_minus*(rho[i][j][k] - rho[i][j][k-1]);

                e4x_plus =  bigger(0.0,v2 - e2x_plus);
                e4x_minus = bigger(0.0,v2 - e2x_minus);
                e4y_plus =  bigger(0.0,v2 - e2y_plus);
                e4y_minus = bigger(0.0,v2 - e2y_minus);
                e4z_plus =  bigger(0.0,v2 - e2z_plus);
                e4z_minus = bigger(0.0,v2 - e2z_minus);

                val -= e4x_plus * (rho[i+4][j][k]-3.0*rho[i+3][j][k]+3.0*rho[i+2][j][k]-rho[i+1][j][k])
                     - e4x_minus *(rho[i+3][j][k]-3.0*rho[i+2][j][k]+3.0*rho[i+1][j][k]-rho[i][j][k])
                     + e4y_plus * (rho[i][j+2][k]-3.0*rho[i][j+1][k]+3.0*rho[i][j][k]-rho[i][j-1][k])
                     - e4y_minus *(rho[i][j+1][k]-3.0*rho[i][j][k]+3.0*rho[i][j-1][k]-rho[i][j-2][k])
                     + e4z_plus * (rho[i][j][k+2]-3.0*rho[i][j][k+1]+3.0*rho[i][j][k]-rho[i][j][k-1])
                     - e4z_minus *(rho[i][j][k+1]-3.0*rho[i][j][k]+3.0*rho[i][j][k-1]-rho[i][j][k-2]);
        }
        else if(boundary_flag[n] == XDOWN) {

                nux_minus = fabs(rho[i][j][k]-2.0*rho[i-1][j][k]+rho[i-2][j][k])/(4.0*rho_air);
                e2x_minus = v1 * nux_minus;
                e2x_plus =  e2x_minus;

                nuy_plus =  fabs(rho[i][j+2][k]-2.0*rho[i][j+1][k]+rho[i][j][k])/(4.0*rho_air);
                nuy =       fabs(rho[i][j+1][k]-2.0*rho[i][j][k]+rho[i][j-1][k])/(4.0*rho_air);
                nuy_minus = fabs(rho[i][j][k]-2.0*rho[i][j-1][k]+rho[i][j-2][k])/(4.0*rho_air);
                e2y_plus =  v1 * bigger(nuy_plus,nuy);
                e2y_minus = v1 * bigger(nuy_minus,nuy);

                nuz_plus =  fabs(rho[i][j][k+2]-2.0*rho[i][j][k+1]+rho[i][j][k])/(4.0*rho_air);
                nuz =       fabs(rho[i][j][k+1]-2.0*rho[i][j][k]+rho[i][j][k-1])/(4.0*rho_air);
                nuz_minus = fabs(rho[i][j][k]-2.0*rho[i][j][k-1]+rho[i][j][k-2])/(4.0*rho_air);
                e2z_plus =  v1 * bigger(nuz_plus,nuz);
                e2z_minus = v1 * bigger(nuz_minus,nuz);

                val = e2x_plus*(rho[i][j][k] - rho[i-1][j][k]) - e2x_minus*(rho[i-1][j][k] - rho[i-2][j][k])
                    + e2y_plus*(rho[i][j+1][k] - rho[i][j][k]) - e2y_minus*(rho[i][j][k] - rho[i][j-1][k])
                    + e2z_plus*(rho[i][j][k+1] - rho[i][j][k]) - e2z_minus*(rho[i][j][k] - rho[i][j][k-1]);

                e4x_plus =  bigger(0.0,v2 - e2x_plus);
                e4x_minus = bigger(0.0,v2 - e2x_minus);
                e4y_plus =  bigger(0.0,v2 - e2y_plus);
                e4y_minus = bigger(0.0,v2 - e2y_minus);
                e4z_plus =  bigger(0.0,v2 - e2z_plus);
                e4z_minus = bigger(0.0,v2 - e2z_minus);

                val -= e4x_plus * (rho[i][j][k]-3.0*rho[i-1][j][k]+3.0*rho[i-2][j][k]-rho[i-3][j][k])
                     - e4x_minus *(rho[i-1][j][k]-3.0*rho[i-2][j][k]+3.0*rho[i-3][j][k]-rho[i-4][j][k])
                     + e4y_plus * (rho[i][j+2][k]-3.0*rho[i][j+1][k]+3.0*rho[i][j][k]-rho[i][j-1][k])
                     - e4y_minus *(rho[i][j+1][k]-3.0*rho[i][j][k]+3.0*rho[i][j-1][k]-rho[i][j-2][k])
                     + e4z_plus * (rho[i][j][k+2]-3.0*rho[i][j][k+1]+3.0*rho[i][j][k]-rho[i][j][k-1])
                     - e4z_minus *(rho[i][j][k+1]-3.0*rho[i][j][k]+3.0*rho[i][j][k-1]-rho[i][j][k-2]);

        }
        else if(boundary_flag[n] == YUP) {

                nux_plus =  fabs(rho[i+2][j][k]-2.0*rho[i+1][j][k]+rho[i][j][k])/(4.0*rho_air);
                nux =       fabs(rho[i+1][j][k]-2.0*rho[i][j][k]+rho[i-1][j][k])/(4.0*rho_air);
                nux_minus = fabs(rho[i][j][k]-2.0*rho[i-1][j][k]+rho[i-2][j][k])/(4.0*rho_air);
                e2x_plus =  v1 * bigger(nux_plus,nux);
                e2x_minus = v1 * bigger(nux_minus,nux);

                nuy_plus =  fabs(rho[i][j+2][k]-2.0*rho[i][j+1][k]+rho[i][j][k])/(4.0*rho_air);
                e2y_plus =  v1 * nuy_plus;
                e2y_minus = e2y_plus;

                nuz_plus =  fabs(rho[i][j][k+2]-2.0*rho[i][j][k+1]+rho[i][j][k])/(4.0*rho_air);
                nuz =       fabs(rho[i][j][k+1]-2.0*rho[i][j][k]+rho[i][j][k-1])/(4.0*rho_air);
                nuz_minus = fabs(rho[i][j][k]-2.0*rho[i][j][k-1]+rho[i][j][k-2])/(4.0*rho_air);
                e2z_plus =  v1 * bigger(nuz_plus,nuz);
                e2z_minus = v1 * bigger(nuz_minus,nuz);

                val = e2x_plus*(rho[i+1][j][k] - rho[i][j][k]) - e2x_minus*(rho[i][j][k] - rho[i-1][j][k])
                    + e2y_plus*(rho[i][j+2][k] - rho[i][j+1][k]) - e2y_minus*(rho[i][j+1][k] - rho[i][j][k])
                    + e2z_plus*(rho[i][j][k+1] - rho[i][j][k]) - e2z_minus*(rho[i][j][k] - rho[i][j][k-1]);

                e4x_plus =  bigger(0.0,v2 - e2x_plus);
                e4x_minus = bigger(0.0,v2 - e2x_minus);
                e4y_plus =  bigger(0.0,v2 - e2y_plus);
                e4y_minus = bigger(0.0,v2 - e2y_minus);
                e4z_plus =  bigger(0.0,v2 - e2z_plus);
                e4z_minus = bigger(0.0,v2 - e2z_minus);

                val -= e4x_plus * (rho[i+2][j][k]-3.0*rho[i+1][j][k]+3.0*rho[i][j][k]-rho[i-1][j][k])
                     - e4x_minus *(rho[i+1][j][k]-3.0*rho[i][j][k]+3.0*rho[i-1][j][k]-rho[i-2][j][k])
                     + e4y_plus * (rho[i][j+4][k]-3.0*rho[i][j+3][k]+3.0*rho[i][j+2][k]-rho[i][j+1][k])
                     - e4y_minus *(rho[i][j+3][k]-3.0*rho[i][j+2][k]+3.0*rho[i][j+1][k]-rho[i][j][k])
                     + e4z_plus * (rho[i][j][k+2]-3.0*rho[i][j][k+1]+3.0*rho[i][j][k]-rho[i][j][k-1])
                     - e4z_minus *(rho[i][j][k+1]-3.0*rho[i][j][k]+3.0*rho[i][j][k-1]-rho[i][j][k-2]);
        
        }
        else if(boundary_flag[n] == YDOWN) {

                nux_plus =  fabs(rho[i+2][j][k]-2.0*rho[i+1][j][k]+rho[i][j][k])/(4.0*rho_air);
                nux =       fabs(rho[i+1][j][k]-2.0*rho[i][j][k]+rho[i-1][j][k])/(4.0*rho_air);
                nux_minus = fabs(rho[i][j][k]-2.0*rho[i-1][j][k]+rho[i-2][j][k])/(4.0*rho_air);
                e2x_plus =  v1 * bigger(nux_plus,nux);
                e2x_minus = v1 * bigger(nux_minus,nux);

                nuy_minus = fabs(rho[i][j][k]-2.0*rho[i][j-1][k]+rho[i][j-2][k])/(4.0*rho_air);
                e2y_minus = v1 * nuy_minus;
                e2y_plus =  e2y_minus;

                nuz_plus =  fabs(rho[i][j][k+2]-2.0*rho[i][j][k+1]+rho[i][j][k])/(4.0*rho_air);
                nuz =       fabs(rho[i][j][k+1]-2.0*rho[i][j][k]+rho[i][j][k-1])/(4.0*rho_air);
                nuz_minus = fabs(rho[i][j][k]-2.0*rho[i][j][k-1]+rho[i][j][k-2])/(4.0*rho_air);
                e2z_plus =  v1 * bigger(nuz_plus,nuz);
                e2z_minus = v1 * bigger(nuz_minus,nuz);

                val = e2x_plus*(rho[i+1][j][k] - rho[i][j][k]) - e2x_minus*(rho[i][j][k] - rho[i-1][j][k])
                    + e2y_plus*(rho[i][j][k] - rho[i][j-1][k]) - e2y_minus*(rho[i][j-1][k] - rho[i][j-2][k])
                    + e2z_plus*(rho[i][j][k+1] - rho[i][j][k]) - e2z_minus*(rho[i][j][k] - rho[i][j][k-1]);

                e4x_plus =  bigger(0.0,v2 - e2x_plus);
                e4x_minus = bigger(0.0,v2 - e2x_minus);
                e4y_plus =  bigger(0.0,v2 - e2y_plus);
                e4y_minus = bigger(0.0,v2 - e2y_minus);
                e4z_plus =  bigger(0.0,v2 - e2z_plus);
                e4z_minus = bigger(0.0,v2 - e2z_minus);

                val -= e4x_plus * (rho[i+2][j][k]-3.0*rho[i+1][j][k]+3.0*rho[i][j][k]-rho[i-1][j][k])
                     - e4x_minus *(rho[i+1][j][k]-3.0*rho[i][j][k]+3.0*rho[i-1][j][k]-rho[i-2][j][k])
                     + e4y_plus * (rho[i][j][k]-3.0*rho[i][j-1][k]+3.0*rho[i][j-2][k]-rho[i][j-3][k])
                     - e4y_minus *(rho[i][j-1][k]-3.0*rho[i][j-2][k]+3.0*rho[i][j-3][k]-rho[i][j-4][k])
                     + e4z_plus * (rho[i][j][k+2]-3.0*rho[i][j][k+1]+3.0*rho[i][j][k]-rho[i][j][k-1])
                     - e4z_minus *(rho[i][j][k+1]-3.0*rho[i][j][k]+3.0*rho[i][j][k-1]-rho[i][j][k-2]);

        }
        else if(boundary_flag[n] == ZUP) {

                nux_plus =  fabs(rho[i+2][j][k]-2.0*rho[i+1][j][k]+rho[i][j][k])/(4.0*rho_air);
                nux =       fabs(rho[i+1][j][k]-2.0*rho[i][j][k]+rho[i-1][j][k])/(4.0*rho_air);
                nux_minus = fabs(rho[i][j][k]-2.0*rho[i-1][j][k]+rho[i-2][j][k])/(4.0*rho_air);
                e2x_plus =  v1 * bigger(nux_plus,nux);
                e2x_minus = v1 * bigger(nux_minus,nux);

                nuy_plus =  fabs(rho[i][j+2][k]-2.0*rho[i][j+1][k]+rho[i][j][k])/(4.0*rho_air);
                nuy =       fabs(rho[i][j+1][k]-2.0*rho[i][j][k]+rho[i][j-1][k])/(4.0*rho_air);
                nuy_minus = fabs(rho[i][j][k]-2.0*rho[i][j-1][k]+rho[i][j-2][k])/(4.0*rho_air);
                e2y_plus =  v1 * bigger(nuy_plus,nuy);
                e2y_minus = v1 * bigger(nuy_minus,nuy);

                nuz_plus =  fabs(rho[i][j][k+2]-2.0*rho[i][j][k+1]+rho[i][j][k])/(4.0*rho_air);
                e2z_plus =  v1 * nuz_plus;
                e2z_minus = e2z_plus;

                val = e2x_plus*(rho[i+1][j][k] - rho[i][j][k]) - e2x_minus*(rho[i][j][k] - rho[i-1][j][k])
                    + e2y_plus*(rho[i][j+1][k] - rho[i][j][k]) - e2y_minus*(rho[i][j][k] - rho[i][j-1][k])
                    + e2z_plus*(rho[i][j][k+2] - rho[i][j][k+1]) - e2z_minus*(rho[i][j][k+1] - rho[i][j][k]);

                e4x_plus =  bigger(0.0,v2 - e2x_plus);
                e4x_minus = bigger(0.0,v2 - e2x_minus);
                e4y_plus =  bigger(0.0,v2 - e2y_plus);
                e4y_minus = bigger(0.0,v2 - e2y_minus);
                e4z_plus =  bigger(0.0,v2 - e2z_plus);
                e4z_minus = bigger(0.0,v2 - e2z_minus);

                val -= e4x_plus * (rho[i+2][j][k]-3.0*rho[i+1][j][k]+3.0*rho[i][j][k]-rho[i-1][j][k])
                     - e4x_minus *(rho[i+1][j][k]-3.0*rho[i][j][k]+3.0*rho[i-1][j][k]-rho[i-2][j][k])
                     + e4y_plus * (rho[i][j+2][k]-3.0*rho[i][j+1][k]+3.0*rho[i][j][k]-rho[i][j-1][k])
                     - e4y_minus *(rho[i][j+1][k]-3.0*rho[i][j][k]+3.0*rho[i][j-1][k]-rho[i][j-2][k])
                     + e4z_plus * (rho[i][j][k+4]-3.0*rho[i][j][k+3]+3.0*rho[i][j][k+2]-rho[i][j][k+1])
                     - e4z_minus *(rho[i][j][k+3]-3.0*rho[i][j][k+2]+3.0*rho[i][j][k+1]-rho[i][j][k]);
        
	}
        else if(boundary_flag[n] == ZDOWN) {

                nux_plus =  fabs(rho[i+2][j][k]-2.0*rho[i+1][j][k]+rho[i][j][k])/(4.0*rho_air);
                nux =       fabs(rho[i+1][j][k]-2.0*rho[i][j][k]+rho[i-1][j][k])/(4.0*rho_air);
                nux_minus = fabs(rho[i][j][k]-2.0*rho[i-1][j][k]+rho[i-2][j][k])/(4.0*rho_air);
                e2x_plus =  v1 * bigger(nux_plus,nux);
                e2x_minus = v1 * bigger(nux_minus,nux);

                nuy_plus =  fabs(rho[i][j+2][k]-2.0*rho[i][j+1][k]+rho[i][j][k])/(4.0*rho_air);
                nuy =       fabs(rho[i][j+1][k]-2.0*rho[i][j][k]+rho[i][j-1][k])/(4.0*rho_air);
                nuy_minus = fabs(rho[i][j][k]-2.0*rho[i][j-1][k]+rho[i][j-2][k])/(4.0*rho_air);
                e2y_plus =  v1 * bigger(nuy_plus,nuy);
                e2y_minus = v1 * bigger(nuy_minus,nuy);

                nuz_minus = fabs(rho[i][j][k]-2.0*rho[i][j][k-1]+rho[i][j][k-2])/(4.0*rho_air);
                e2z_minus = v1 * nuz_minus;
                e2z_plus =  e2z_minus;

                val = e2x_plus*(rho[i+1][j][k] - rho[i][j][k]) - e2x_minus*(rho[i][j][k] - rho[i-1][j][k])
                    + e2y_plus*(rho[i][j+1][k] - rho[i][j][k]) - e2y_minus*(rho[i][j][k] - rho[i][j-1][k])
                    + e2z_plus*(rho[i][j][k] - rho[i][j][k-1]) - e2z_minus*(rho[i][j][k-1] - rho[i][j][k-2]);

                e4x_plus =  bigger(0.0,v2 - e2x_plus);
                e4x_minus = bigger(0.0,v2 - e2x_minus);
                e4y_plus =  bigger(0.0,v2 - e2y_plus);
                e4y_minus = bigger(0.0,v2 - e2y_minus);
                e4z_plus =  bigger(0.0,v2 - e2z_plus);
                e4z_minus = bigger(0.0,v2 - e2z_minus);

                val -= e4x_plus * (rho[i+2][j][k]-3.0*rho[i+1][j][k]+3.0*rho[i][j][k]-rho[i-1][j][k])
                     - e4x_minus *(rho[i+1][j][k]-3.0*rho[i][j][k]+3.0*rho[i-1][j][k]-rho[i-2][j][k])
                     + e4y_plus * (rho[i][j+2][k]-3.0*rho[i][j+1][k]+3.0*rho[i][j][k]-rho[i][j-1][k])
                     - e4y_minus *(rho[i][j+1][k]-3.0*rho[i][j][k]+3.0*rho[i][j-1][k]-rho[i][j-2][k])
                     + e4z_plus * (rho[i][j][k]-3.0*rho[i][j][k-1]+3.0*rho[i][j][k-2]-rho[i][j][k-3])
                     - e4z_minus *(rho[i][j][k-1]-3.0*rho[i][j][k-2]+3.0*rho[i][j][k-3]-rho[i][j][k-4]);

	}
        else {
                val = 0.0;
        }

        return(val);
}
/*
 *      this is only used for dealing with 
 *      on the boundaries of the simulation region
 *
 *      v1 and v2 are the viscosity coefficients
 *
 *      note that the four corners are skipped - no viscosity there
 */
double
artificial_viscosity_on_boundary(int i,int j,int k,double v1_0,double v2_0)
{
        double val;
        double e2x_plus,e4x_plus;
        double e2x_minus,e4x_minus;
        double e2x,e2y,e2z;
        double e2y_plus,e4y_plus;
        double e2y_minus,e4y_minus;
        double e2z_plus,e4z_plus;
        double e2z_minus,e4z_minus;
        double nux_plus,nux,nux_minus;
        double nuy_plus,nuy,nuy_minus;
        double nuz_plus,nuz,nuz_minus;
	double v1,v2;

//	return(0.0);	// no AV on boundaries

	v1 = 1.0 * v1_0;
	v2 = 1.0 * v2_0;

// first the surface in the y = 0 plane 
// found a mistake in this line (and similar ones that follow) in recorder7c.c -- but since
//	i_max > j_max it probably did not matter!!
        if((j == 0) && ((i > 1) && (i < i_max-1)) && ((k > 1) && (k < k_max-1))) {

                nux_plus =  fabs(rho[i+2][j][k]-2.0*rho[i+1][j][k]+rho[i][j][k])/(4.0*rho_air);
                nux      =  fabs(rho[i+1][j][k]-2.0*rho[i][j][k]+rho[i-1][j][k])/(4.0*rho_air);
                nux_minus =  fabs(rho[i][j][k]-2.0*rho[i-1][j][k]+rho[i-2][j][k])/(4.0*rho_air);
                e2x_plus =  v1 * bigger(nux_plus,nux);
                e2x_minus = v1 * bigger(nux_minus,nux);

                nuy_plus =  fabs(rho[i][j+2][k]-2.0*rho[i][j+1][k]+rho[i][j][k])/(4.0*rho_air);
                e2y_plus =  v1 * nuy_plus;
                e2y_minus = e2y_plus;

                nuz_plus =  fabs(rho[i][j][k+2]-2.0*rho[i][j][k+1]+rho[i][j][k])/(4.0*rho_air);
                nuz      =  fabs(rho[i][j][k+1]-2.0*rho[i][j][k]+rho[i][j][k-1])/(4.0*rho_air);
                nuz_minus =  fabs(rho[i][j][k]-2.0*rho[i][j][k-1]+rho[i][j][k-2])/(4.0*rho_air);
                e2z_plus =  v1 * bigger(nuz_plus,nuz);
                e2z_minus = v1 * bigger(nuz_minus,nuz);

                val = e2x_plus*(rho[i+1][j][k] - rho[i][j][k]) - e2x_minus*(rho[i][j][k] - rho[i-1][j][k])
                    + e2y_plus*(rho[i][j+2][k] - rho[i][j+1][k]) - e2y_minus*(rho[i][j+1][k] - rho[i][j][k])
                    + e2z_plus*(rho[i][j][k+1] - rho[i][j][k]) - e2z_minus*(rho[i][j][k] - rho[i][j][k-1]);

                e4x_plus =  bigger(0.0,v2 - e2x_plus);
                e4x_minus = bigger(0.0,v2 - e2x_minus);
                e4y_plus =  bigger(0.0,v2 - e2y_plus);
                e4y_minus = bigger(0.0,v2 - e2y_minus);
                e4z_plus =  bigger(0.0,v2 - e2z_plus);
                e4z_minus = bigger(0.0,v2 - e2z_minus);

                val -= e4x_plus * (rho[i+2][j][k]-3.0*rho[i+1][j][k]+3.0*rho[i][j][k]-rho[i-1][j][k])
                     - e4x_minus *(rho[i+1][j][k]-3.0*rho[i][j][k]+3.0*rho[i-1][j][k]-rho[i-2][j][k])
                     + e4y_plus * (rho[i][j+4][k]-3.0*rho[i][j+3][k]+3.0*rho[i][j+2][k]-rho[i][j+1][k])
                     - e4y_minus *(rho[i][j+3][k]-3.0*rho[i][j+2][k]+3.0*rho[i][j+1][k]-rho[i][j][k])
                     + e4z_plus * (rho[i][j][k+2]-3.0*rho[i][j][k+1]+3.0*rho[i][j][k]-rho[i][j][k-1])
                     - e4z_minus *(rho[i][j][k+1]-3.0*rho[i][j][k]+3.0*rho[i][j][k-1]-rho[i][j][k-2]);
// fix the above lines in v. 4 here and below
        }
// next the surface in the y = y_max plane
        else if((j == j_max) && ((i > 1) && (i < i_max-1)) && ((k > 1) && (k < k_max-1))) {

                nux_plus =  fabs(rho[i+2][j][k]-2.0*rho[i+1][j][k]+rho[i][j][k])/(4.0*rho_air);
                nux      =  fabs(rho[i+1][j][k]-2.0*rho[i][j][k]+rho[i-1][j][k])/(4.0*rho_air);
                nux_minus =  fabs(rho[i][j][k]-2.0*rho[i-1][j][k]+rho[i-2][j][k])/(4.0*rho_air);
                e2x_plus =  v1 * bigger(nux_plus,nux);
                e2x_minus = v1 * bigger(nux_minus,nux);

                nuy_minus = fabs(rho[i][j][k]-2.0*rho[i][j-1][k]+rho[i][j-2][k])/(4.0*rho_air);
                e2y_minus = v1 * nuy_minus;
                e2y_plus =  e2y_minus;

                nuz_plus =  fabs(rho[i][j][k+2]-2.0*rho[i][j][k+1]+rho[i][j][k])/(4.0*rho_air);
                nuz      =  fabs(rho[i][j][k+1]-2.0*rho[i][j][k]+rho[i][j][k-1])/(4.0*rho_air);
                nuz_minus =  fabs(rho[i][j][k]-2.0*rho[i][j][k-1]+rho[i][j][k-2])/(4.0*rho_air);
                e2z_plus =  v1 * bigger(nuz_plus,nuz);
                e2z_minus = v1 * bigger(nuz_minus,nuz);

                val = e2x_plus*(rho[i+1][j][k] - rho[i][j][k]) - e2x_minus*(rho[i][j][k] - rho[i-1][j][k])
                    + e2y_plus*(rho[i][j][k] - rho[i][j-1][k]) - e2y_minus*(rho[i][j-1][k] - rho[i][j-2][k])
                    + e2z_plus*(rho[i][j][k+1] - rho[i][j][k]) - e2z_minus*(rho[i][j][k] - rho[i][j][k-1]);

                e4x_plus =  bigger(0.0,v2 - e2x_plus);
                e4x_minus = bigger(0.0,v2 - e2x_minus);
                e4y_plus =  bigger(0.0,v2 - e2y_plus);
                e4y_minus = bigger(0.0,v2 - e2y_minus);
                e4z_plus =  bigger(0.0,v2 - e2z_plus);
                e4z_minus = bigger(0.0,v2 - e2z_minus);

                val -= e4x_plus * (rho[i+2][j][k]-3.0*rho[i+1][j][k]+3.0*rho[i][j][k]-rho[i-1][j][k])
                     - e4x_minus *(rho[i+1][j][k]-3.0*rho[i][j][k]+3.0*rho[i-1][j][k]-rho[i-2][j][k])
                     + e4y_plus * (rho[i][j][k]-3.0*rho[i][j-1][k]+3.0*rho[i][j-2][k]-rho[i][j-3][k])
                     - e4y_minus *(rho[i][j-1][k]-3.0*rho[i][j-2][k]+3.0*rho[i][j-3][k]-rho[i][j-4][k])
                     + e4z_plus * (rho[i][j][k+2]-3.0*rho[i][j][k+1]+3.0*rho[i][j][k]-rho[i][j][k-1])
                     - e4z_minus *(rho[i][j][k+1]-3.0*rho[i][j][k]+3.0*rho[i][j][k-1]-rho[i][j][k-2]);
        
        }
// next the surface in the x = 0 plane
        else if((i == 0) && ((j > 1) && (j < j_max-1)) && ((k > 1) && (k < k_max-1))) {

                nux_plus =  fabs(rho[i+2][j][k]-2.0*rho[i+1][j][k]+rho[i][j][k])/(4.0*rho_air);
                e2x_plus =  v1 * nux_plus;
// another error found here
                e2x_minus = e2x_plus;

                nuy_plus =  fabs(rho[i][j+2][k]-2.0*rho[i][j+1][k]+rho[i][j][k])/(4.0*rho_air);
                nuy =       fabs(rho[i][j+1][k]-2.0*rho[i][j][k]+rho[i][j-1][k])/(4.0*rho_air);
                nuy_minus = fabs(rho[i][j][k]-2.0*rho[i][j-1][k]+rho[i][j-2][k])/(4.0*rho_air);
                e2y_plus =  v1 * bigger(nuy_plus,nuy);
                e2y_minus = v1 * bigger(nuy_minus,nuy);

                nuz_plus =  fabs(rho[i][j][k+2]-2.0*rho[i][j][k+1]+rho[i][j][k])/(4.0*rho_air);
                nuz      =  fabs(rho[i][j][k+1]-2.0*rho[i][j][k]+rho[i][j][k-1])/(4.0*rho_air);
                nuz_minus =  fabs(rho[i][j][k]-2.0*rho[i][j][k-1]+rho[i][j][k-2])/(4.0*rho_air);
                e2z_plus =  v1 * bigger(nuz_plus,nuz);
                e2z_minus = v1 * bigger(nuz_minus,nuz);

                val = e2x_plus*(rho[i+2][j][k] - rho[i+1][j][k]) - e2x_minus*(rho[i+1][j][k] - rho[i][j][k])
                    + e2y_plus*(rho[i][j+1][k] - rho[i][j][k]) - e2y_minus*(rho[i][j][k] - rho[i][j-1][k])
                    + e2z_plus*(rho[i][j][k+1] - rho[i][j][k]) - e2z_minus*(rho[i][j][k] - rho[i][j][k-1]);
// found this mistake in v8m2!  -- fix it in other sections of this program too
//                    + e2z_plus*(rho[i][j][k+1] - rho[i][j][k]) - e2z_minus*(rho[i][j][k] - rho[i-1][j][k-1]);

                e4x_plus =  bigger(0.0,v2 - e2x_plus);
                e4x_minus = bigger(0.0,v2 - e2x_minus);
                e4y_plus =  bigger(0.0,v2 - e2y_plus);
                e4y_minus = bigger(0.0,v2 - e2y_minus);
                e4z_plus =  bigger(0.0,v2 - e2z_plus);
                e4z_minus = bigger(0.0,v2 - e2z_minus);

                val -= e4x_plus * (rho[i+4][j][k]-3.0*rho[i+3][j][k]+3.0*rho[i+2][j][k]-rho[i+1][j][k])
                     - e4x_minus *(rho[i+3][j][k]-3.0*rho[i+2][j][k]+3.0*rho[i+1][j][k]-rho[i][j][k])
                     + e4y_plus * (rho[i][j+2][k]-3.0*rho[i][j+1][k]+3.0*rho[i][j][k]-rho[i][j-1][k])
                     - e4y_minus *(rho[i][j+1][k]-3.0*rho[i][j][k]+3.0*rho[i][j-1][k]-rho[i][j-2][k])
                     + e4z_plus * (rho[i][j][k+2]-3.0*rho[i][j][k+1]+3.0*rho[i][j][k]-rho[i][j][k-1])
                     - e4z_minus *(rho[i][j][k+1]-3.0*rho[i][j][k]+3.0*rho[i][j][k-1]-rho[i][j][k-2]);
        }
// next the surface in the x = x_max plane
        else if((i == i_max) && ((j > 1) && (j < j_max-1)) && ((k > 1) && (k < k_max-1))) {

                nux_minus = fabs(rho[i][j][k]-2.0*rho[i-1][j][k]+rho[i-2][j][k])/(4.0*rho_air);
                e2x_minus = v1 * nux_minus;
                e2x_plus =  e2x_minus;

                nuy_plus =  fabs(rho[i][j+2][k]-2.0*rho[i][j+1][k]+rho[i][j][k])/(4.0*rho_air);
                nuy =       fabs(rho[i][j+1][k]-2.0*rho[i][j][k]+rho[i][j-1][k])/(4.0*rho_air);
                nuy_minus = fabs(rho[i][j][k]-2.0*rho[i][j-1][k]+rho[i][j-2][k])/(4.0*rho_air);
                e2y_plus =  v1 * bigger(nuy_plus,nuy);
                e2y_minus = v1 * bigger(nuy_minus,nuy);

                nuz_plus =  fabs(rho[i][j][k+2]-2.0*rho[i][j][k+1]+rho[i][j][k])/(4.0*rho_air);
                nuz      =  fabs(rho[i][j][k+1]-2.0*rho[i][j][k]+rho[i][j][k-1])/(4.0*rho_air);
                nuz_minus =  fabs(rho[i][j][k]-2.0*rho[i][j][k-1]+rho[i][j][k-2])/(4.0*rho_air);
                e2z_plus =  v1 * bigger(nuz_plus,nuz);
                e2z_minus = v1 * bigger(nuz_minus,nuz);

                val = e2x_plus*(rho[i][j][k] - rho[i-1][j][k]) - e2x_minus*(rho[i-1][j][k] - rho[i-2][j][k])
                    + e2y_plus*(rho[i][j+1][k] - rho[i][j][k]) - e2y_minus*(rho[i][j][k] - rho[i][j-1][k])
                    + e2z_plus*(rho[i][j][k+1] - rho[i][j][k]) - e2z_minus*(rho[i][j][k] - rho[i][j][k-1]);

                e4x_plus =  bigger(0.0,v2 - e2x_plus);
                e4x_minus = bigger(0.0,v2 - e2x_minus);
                e4y_plus =  bigger(0.0,v2 - e2y_plus);
                e4y_minus = bigger(0.0,v2 - e2y_minus);
                e4z_plus =  bigger(0.0,v2 - e2z_plus);
                e4z_minus = bigger(0.0,v2 - e2z_minus);

                val -= e4x_plus * (rho[i][j][k]-3.0*rho[i-1][j][k]+3.0*rho[i-2][j][k]-rho[i-3][j][k])
                     - e4x_minus *(rho[i-1][j][k]-3.0*rho[i-2][j][k]+3.0*rho[i-3][j][k]-rho[i-4][j][k])
                     + e4y_plus * (rho[i][j+2][k]-3.0*rho[i][j+1][k]+3.0*rho[i][j][k]-rho[i][j-1][k])
                     - e4y_minus *(rho[i][j+1][k]-3.0*rho[i][j][k]+3.0*rho[i][j-1][k]-rho[i][j-2][k])
                     + e4z_plus * (rho[i][j][k+2]-3.0*rho[i][j][k+1]+3.0*rho[i][j][k]-rho[i][j][k-1])
                     - e4z_minus *(rho[i][j][k+1]-3.0*rho[i][j][k]+3.0*rho[i][j][k-1]-rho[i][j][k-2]);

        }
// next the surface in the z = 0 plane
        else if((k == 0) && ((i > 1) && (i < i_max-1)) && ((j > 1) && (j < j_max-1))) {

                nux_plus =  fabs(rho[i+2][j][k]-2.0*rho[i+1][j][k]+rho[i][j][k])/(4.0*rho_air);
                nux      =  fabs(rho[i+1][j][k]-2.0*rho[i][j][k]+rho[i-1][j][k])/(4.0*rho_air);
                nux_minus =  fabs(rho[i][j][k]-2.0*rho[i-1][j][k]+rho[i-2][j][k])/(4.0*rho_air);
                e2x_plus =  v1 * bigger(nux_plus,nux);
                e2x_minus = v1 * bigger(nux_minus,nux);

                nuy_plus =  fabs(rho[i][j+2][k]-2.0*rho[i][j+1][k]+rho[i][j][k])/(4.0*rho_air);
                nuy =       fabs(rho[i][j+1][k]-2.0*rho[i][j][k]+rho[i][j-1][k])/(4.0*rho_air);
                nuy_minus = fabs(rho[i][j][k]-2.0*rho[i][j-1][k]+rho[i][j-2][k])/(4.0*rho_air);
                e2y_plus =  v1 * bigger(nuy_plus,nuy);
                e2y_minus = v1 * bigger(nuy_minus,nuy);

                nuz_plus =  fabs(rho[i][j][k+2]-2.0*rho[i][j][k+1]+rho[i][j][k])/(4.0*rho_air);
                e2z_plus =  v1 * nuz_plus;
                e2z_minus = e2z_plus;

                val = e2x_plus*(rho[i+1][j][k] - rho[i][j][k]) - e2x_minus*(rho[i][j][k] - rho[i-1][j][k])
                    + e2y_plus*(rho[i][j+1][k] - rho[i][j][k]) - e2y_minus*(rho[i][j][k] - rho[i][j-1][k])
                    + e2z_plus*(rho[i][j][k+2] - rho[i][j][k+1]) - e2z_minus*(rho[i][j][k+1] - rho[i][j][k]);

                e4x_plus =  bigger(0.0,v2 - e2x_plus);
                e4x_minus = bigger(0.0,v2 - e2x_minus);
                e4y_plus =  bigger(0.0,v2 - e2y_plus);
                e4y_minus = bigger(0.0,v2 - e2y_minus);
                e4z_plus =  bigger(0.0,v2 - e2z_plus);
                e4z_minus = bigger(0.0,v2 - e2z_minus);

                val -= e4x_plus * (rho[i+2][j][k]-3.0*rho[i+1][j][k]+3.0*rho[i][j][k]-rho[i-1][j][k])
                     - e4x_minus *(rho[i+1][j][k]-3.0*rho[i][j][k]+3.0*rho[i-1][j][k]-rho[i-2][j][k])
                     + e4y_plus * (rho[i][j+2][k]-3.0*rho[i][j+1][k]+3.0*rho[i][j][k]-rho[i][j-1][k])
                     - e4y_minus *(rho[i][j+1][k]-3.0*rho[i][j][k]+3.0*rho[i][j-1][k]-rho[i][j-2][k])
                     + e4z_plus * (rho[i][j][k+4]-3.0*rho[i][j][k+3]+3.0*rho[i][j][k+2]-rho[i][j][k+1])
                     - e4z_minus *(rho[i][j][k+3]-3.0*rho[i][j][k+2]+3.0*rho[i][j][k+1]-rho[i][j][k]);
        }
// next the surface in the z = z_max plane
        else if((k == k_max) && ((i > 1) && (i < i_max-1)) && ((j > 1) && (j < j_max-1))) {

                nux_plus =  fabs(rho[i+2][j][k]-2.0*rho[i+1][j][k]+rho[i][j][k])/(4.0*rho_air);
                nux      =  fabs(rho[i+1][j][k]-2.0*rho[i][j][k]+rho[i-1][j][k])/(4.0*rho_air);
                nux_minus =  fabs(rho[i][j][k]-2.0*rho[i-1][j][k]+rho[i-2][j][k])/(4.0*rho_air);
                e2x_plus =  v1 * bigger(nux_plus,nux);
                e2x_minus = v1 * bigger(nux_minus,nux);

                nuy_plus =  fabs(rho[i][j+2][k]-2.0*rho[i][j+1][k]+rho[i][j][k])/(4.0*rho_air);
                nuy =       fabs(rho[i][j+1][k]-2.0*rho[i][j][k]+rho[i][j-1][k])/(4.0*rho_air);
                nuy_minus = fabs(rho[i][j][k]-2.0*rho[i][j-1][k]+rho[i][j-2][k])/(4.0*rho_air);
                e2y_plus =  v1 * bigger(nuy_plus,nuy);
                e2y_minus = v1 * bigger(nuy_minus,nuy);

                nuz_minus = fabs(rho[i][j][k]-2.0*rho[i][j][k-1]+rho[i][j][k-2])/(4.0*rho_air);
                e2z_minus = v1 * nuz_minus;
                e2z_plus =  e2z_minus;

                val = e2x_plus*(rho[i+1][j][k] - rho[i][j][k]) - e2x_minus*(rho[i][j][k] - rho[i-1][j][k])
                    + e2y_plus*(rho[i][j+1][k] - rho[i][j][k]) - e2y_minus*(rho[i][j][k] - rho[i][j-1][k])
                    + e2z_plus*(rho[i][j][k] - rho[i][j][k-1]) - e2z_minus*(rho[i][j][k-1] - rho[i][j][k-2]);

                e4x_plus =  bigger(0.0,v2 - e2x_plus);
                e4x_minus = bigger(0.0,v2 - e2x_minus);
                e4y_plus =  bigger(0.0,v2 - e2y_plus);
                e4y_minus = bigger(0.0,v2 - e2y_minus);
                e4z_plus =  bigger(0.0,v2 - e2z_plus);
                e4z_minus = bigger(0.0,v2 - e2z_minus);

                val -= e4x_plus * (rho[i+2][j][k]-3.0*rho[i+1][j][k]+3.0*rho[i][j][k]-rho[i-1][j][k])
                     - e4x_minus *(rho[i+1][j][k]-3.0*rho[i][j][k]+3.0*rho[i-1][j][k]-rho[i-2][j][k])
                     + e4y_plus * (rho[i][j+2][k]-3.0*rho[i][j+1][k]+3.0*rho[i][j][k]-rho[i][j-1][k])
                     - e4y_minus *(rho[i][j+1][k]-3.0*rho[i][j][k]+3.0*rho[i][j-1][k]-rho[i][j-2][k])
                     + e4z_plus * (rho[i][j][k]-3.0*rho[i][j][k-1]+3.0*rho[i][j][k-2]-rho[i][j][k-3])
                     - e4z_minus *(rho[i][j][k-1]-3.0*rho[i][j][k-2]+3.0*rho[i][j][k-3]-rho[i][j][k-4]);

        }
        else {
                val = 0.0;
        }

        return(val);
}

/*
 *	reset (i.e., set to zero) the arrays used to accumulate averaging data for rho, u, and v
 */
int
zero_filtering_data()
{
	int i,j,k;

{

#ifdef CLUSTER
#pragma omp collapse(3)
#pragma omp parallel for shared(u_ave,v_ave,w_ave,rho_ave)  private(i,j,k) 
#endif

	for(i = 0; i <= i_max; i++) {
		for(j = 0; j <= j_max; j++) {
			for(k = 0; k <= k_max; k++) {
				rho_ave[i][j][k] = u_ave[i][j][k] = v_ave[i][j][k] = w_ave[i][j][k] = 0.0;
			}
		}
	}

}

	di_center_ave[LEFT][CURRENT] = di_center_ave[LEFT][OLD] = 0.0;
	dj_center_ave[LEFT][CURRENT] = dj_center_ave[LEFT][OLD] = 0.0;
	di_center_ave[RIGHT][CURRENT] = di_center_ave[RIGHT][OLD] = 0.0;
	dj_center_ave[RIGHT][CURRENT] = dj_center_ave[RIGHT][OLD] = 0.0;

	dj_center_interior_ave[LEFT][CURRENT] = dj_center_interior_ave[LEFT][OLD] = 0.0;
	dj_center_interior_ave[RIGHT][CURRENT] = dj_center_interior_ave[RIGHT][OLD] = 0.0;
	di_center_interior_ave[LEFT][CURRENT] = di_center_interior_ave[LEFT][OLD] = 0.0;
	di_center_interior_ave[RIGHT][CURRENT] = di_center_interior_ave[RIGHT][OLD] = 0.0;

	return(0);
}

/*
 *	accumulate data for rho, u, and v as part of filtering process
 */
int
accum_filtering_data()
{
	int i,j,k;

{

#ifdef CLUSTER
#pragma omp collapse(3)
#pragma omp parallel for shared(u,v,w,rho,u_ave,v_ave,w_ave,rho_ave)  private(i,j,k) 
#endif

	for(i = 0; i <= i_max; i++) {
		for(j = 0; j <= j_max; j++) {
			for(k = 0; k <= k_max; k++) {
				rho_ave[i][j][k] += rho[i][j][k];
				u_ave[i][j][k] += u[i][j][k];
				v_ave[i][j][k] += v[i][j][k];
				w_ave[i][j][k] += w[i][j][k];
			}
		}
	}

}

	di_center_ave[LEFT][CURRENT] += di_center[LEFT][CURRENT];
	di_center_ave[LEFT][OLD] += di_center[LEFT][OLD];
	dj_center_ave[LEFT][CURRENT] += dj_center[LEFT][CURRENT];
	dj_center_ave[LEFT][OLD] += dj_center[LEFT][OLD];

	dj_center_interior_ave[LEFT][CURRENT] += dj_center_interior[LEFT][CURRENT];
	dj_center_interior_ave[LEFT][OLD] += dj_center_interior[LEFT][OLD];
	di_center_interior_ave[LEFT][CURRENT] += di_center_interior[LEFT][CURRENT];
	di_center_interior_ave[LEFT][OLD] += di_center_interior[LEFT][OLD];

	di_center_ave[RIGHT][CURRENT] += di_center[RIGHT][CURRENT];
	di_center_ave[RIGHT][OLD] += di_center[RIGHT][OLD];
	dj_center_ave[RIGHT][CURRENT] += dj_center[RIGHT][CURRENT];
	dj_center_ave[RIGHT][OLD] += dj_center[RIGHT][OLD];

	dj_center_interior_ave[RIGHT][CURRENT] += dj_center_interior[RIGHT][CURRENT];
	dj_center_interior_ave[RIGHT][OLD] += dj_center_interior[RIGHT][OLD];
	di_center_interior_ave[RIGHT][CURRENT] += di_center_interior[RIGHT][CURRENT];
	di_center_interior_ave[RIGHT][OLD] += di_center_interior[RIGHT][OLD];

	return(0);
}

/*
 *	replace current data for rho, u, and v with data accumulated by the filtering
 */
double
reset_filtering_data(int n,double t_a)
{
	int i,j,k;
	double new_t;

	new_t = t_a - t_accum/2.0;
	fprintf(fp_log,"finish filtering rho, u, and v at t = %g\n\treset t to %g\n",t_a,new_t);
	fflush(fp_log);
{

#ifdef CLUSTER
#pragma omp collapse(3)
#pragma omp parallel for shared(n,u,v,rho,w,w_ave,u_ave,v_ave,rho_ave)  private(i,j,k) 
#endif

	for(i = 0; i <= i_max; i++) {
		for(j = 0; j <= j_max; j++) {
			for(k = 0; k <= k_max; k++) {
				rho[i][j][k] = rho_ave[i][j][k] / ((double)n); 
				u[i][j][k] = u_ave[i][j][k] / ((double)n);
				v[i][j][k] = v_ave[i][j][k] / ((double)n);
				w[i][j][k] = w_ave[i][j][k] / ((double)n);
			}
		}
	}

}

// now restore lip data

	di_center[LEFT][CURRENT] = di_center_ave[LEFT][CURRENT] / ((double)n); 
	di_center[LEFT][OLD] = di_center_ave[LEFT][OLD] / ((double)n); 
	dj_center[LEFT][CURRENT] = dj_center_ave[LEFT][CURRENT] / ((double)n); 
	dj_center[LEFT][OLD] = dj_center_ave[LEFT][OLD] / ((double)n); 
	di_center[RIGHT][CURRENT] = di_center_ave[RIGHT][CURRENT] / ((double)n); 
	di_center[RIGHT][OLD] = di_center_ave[RIGHT][OLD] / ((double)n); 
	dj_center[RIGHT][CURRENT] = dj_center_ave[RIGHT][CURRENT] / ((double)n); 
	dj_center[RIGHT][OLD] = dj_center_ave[RIGHT][OLD] / ((double)n); 

	dj_center_interior[LEFT][CURRENT] = dj_center_interior_ave[LEFT][CURRENT] / ((double)n); 
	dj_center_interior[LEFT][OLD] = dj_center_interior_ave[LEFT][OLD] / ((double)n); 
	dj_center_interior[RIGHT][CURRENT] = dj_center_interior_ave[RIGHT][CURRENT] / ((double)n); 
	dj_center_interior[RIGHT][OLD] = dj_center_interior_ave[RIGHT][OLD] / ((double)n); 

	di_center_interior[LEFT][CURRENT] = di_center_interior_ave[LEFT][CURRENT] / ((double)n); 
	di_center_interior[LEFT][OLD] = di_center_interior_ave[LEFT][OLD] / ((double)n); 
	di_center_interior[RIGHT][CURRENT] = di_center_interior_ave[RIGHT][CURRENT] / ((double)n); 
	di_center_interior[RIGHT][OLD] = di_center_interior_ave[RIGHT][OLD] / ((double)n); 

	i_center[LEFT][CURRENT] = i_origin[LEFT] + di_center[LEFT][CURRENT];
	i_center[LEFT][OLD] = i_origin[LEFT] + di_center[LEFT][OLD];
	j_center[LEFT][CURRENT] = j_origin[LEFT] + dj_center[LEFT][CURRENT];
	j_center[LEFT][OLD] = j_origin[LEFT] + dj_center[LEFT][OLD];

	i_center[RIGHT][CURRENT] = i_origin[RIGHT] + di_center[RIGHT][CURRENT];
	i_center[RIGHT][OLD] = i_origin[RIGHT] + di_center[RIGHT][OLD];
	j_center[RIGHT][CURRENT] = j_origin[RIGHT] + dj_center[RIGHT][CURRENT];
	j_center[RIGHT][OLD] = j_origin[RIGHT] + dj_center[RIGHT][OLD];

	update_lip_geometry_v2(QUIET);
	calc_site_weights();

// probably need to do some more work here to make sure values of rho,u,v,w are consistent on and
// near ghost sites

	return(new_t);
}

/*
 *	second deriv of q with respect to x at grid point i,j,k
 */
double
second_deriv_x(float ***q,int i, int j, int k)
{
	double val;

	val = (2.0/(dx_grid[i]+dx_grid[i-1]))*
		(((q[i+1][j][k]-q[i][j][k])/(dx_grid[i])) - ((q[i][j][k]-q[i-1][j][k])/(dx_grid[i-1])));

	return(val);
}

/*
 *	second deriv of q with respect to y at grid point i,j,k
 */
double
second_deriv_y(float ***q,int i, int j, int k)
{
	double val;

	val = (2.0/(dy_grid[j]+dy_grid[j-1]))*
		(((q[i][j+1][k]-q[i][j][k])/(dy_grid[j])) - ((q[i][j][k]-q[i][j-1][k])/(dy_grid[j-1])));

	return(val);
}

/*
 *	second deriv of q with respect to z at grid point i,j,k
 */
double
second_deriv_z(float ***q,int i, int j, int k)
{
	double val;

	val = (2.0/(dz_grid[k]+dz_grid[k-1]))*
		(((q[i][j][k+1]-q[i][j][k])/(dz_grid[k])) - ((q[i][j][k]-q[i][j][k-1])/(dz_grid[k-1])));

	return(val);
}

/*
 *	general routine to dynamically creat/allocate
 *	a three dimensional array of floats of size [nx][ny][nz]
 *
 *	the user passes to the subroutine a pointer of type (float ***) and 
 *	three integers which are the desired dimensions of the array
 *
 *	the routine allocates memory for the array which can then be 
 *	passed to other routines as simply a and accessed as a[i][j][k]
 *
 *	at the end of the program the routine cleanup_array() should be called
 *	to free the allocated memory
 */

float ***allocate_array_of_floats(int nx, int ny, int nz)
{
	float ***a;
	int i,j;

	a = (float ***)malloc(nx * sizeof(float **));
	if(a == NULL) {
		fprintf(stderr,"first malloc failed");
		exit(0);
	}
	a[0] = (float **)malloc(nx * ny * sizeof(float *));
	if(a[0] == NULL) {
		fprintf(stderr,"second (medium size) malloc failed");
		exit(0);
	}
	a[0][0] = (float *)malloc(nx * ny * nz * sizeof(float));
	if(a[0][0] == NULL) {
		fprintf(stderr,"third (big) malloc failed");
		exit(0);
	}
	for(j = 1; j < ny; j++) {
		a[0][j] = a[0][j-1] + nz;
	}
	for(i = 1; i < nx; i++) {
		a[i] = a[i-1] + ny;
		a[i][0] = a[i-1][ny - 1] + nz;
		for(j = 1; j < ny; j++) {
			a[i][j] = a[i][j-1] + nz;
		}
	}

	return(a);
}

int
cleanup_array(float ***a)
{
	free(a[0][0]);
	free(a[0]);
	free(a);

	return(0);
}

/* 
 *	routine to allocate a 3d array of integers
 */

int ***allocate_array_of_integers(int nx, int ny, int nz)
{
	int ***a;
	int i,j;

	a = (int ***)malloc(nx * sizeof(int **));
	if(a == NULL) {
		fprintf(stderr,"first malloc failed");
		exit(0);
	}
	a[0] = (int **)malloc(nx * ny * sizeof(int *));
	if(a[0] == NULL) {
		fprintf(stderr,"second (medium size) malloc failed");
		exit(0);
	}
	a[0][0] = (int *)malloc(nx * ny * nz * sizeof(int));
	if(a[0][0] == NULL) {
		fprintf(stderr,"third (big) malloc failed");
		exit(0);
	}
	for(j = 1; j < ny; j++) {
		a[0][j] = a[0][j-1] + nz;
	}
	for(i = 1; i < nx; i++) {
		a[i] = a[i-1] + ny;
		a[i][0] = a[i-1][ny - 1] + nz;
		for(j = 1; j < ny; j++) {
			a[i][j] = a[i][j-1] + nz;
		}
	}

	return(a);
}
/*
 *	allocate space for the many arrays of floats that are needed
 *	make them all of size [i_max+2][j_max+2][k_max+2] just to be sure
 */

int
create_arrays()
{

	rho = allocate_array_of_floats(i_max+2,j_max+2,k_max+2);
	u = allocate_array_of_floats(i_max+2,j_max+2,k_max+2);
	v = allocate_array_of_floats(i_max+2,j_max+2,k_max+2);
	w = allocate_array_of_floats(i_max+2,j_max+2,k_max+2);

	rho_predictor = allocate_array_of_floats(i_max+2,j_max+2,k_max+2);
	u_predictor = allocate_array_of_floats(i_max+2,j_max+2,k_max+2);
	v_predictor = allocate_array_of_floats(i_max+2,j_max+2,k_max+2);
	w_predictor = allocate_array_of_floats(i_max+2,j_max+2,k_max+2);

	rho_ave = allocate_array_of_floats(i_max+2,j_max+2,k_max+2);
	u_ave = allocate_array_of_floats(i_max+2,j_max+2,k_max+2);
	v_ave = allocate_array_of_floats(i_max+2,j_max+2,k_max+2);
	w_ave = allocate_array_of_floats(i_max+2,j_max+2,k_max+2);

	rho_buf = allocate_array_of_floats(i_max+2,j_max+2,k_max+2);
	u_buf = allocate_array_of_floats(i_max+2,j_max+2,k_max+2);
	v_buf = allocate_array_of_floats(i_max+2,j_max+2,k_max+2);
	w_buf = allocate_array_of_floats(i_max+2,j_max+2,k_max+2);

	site_weight = allocate_array_of_floats(i_max+2,j_max+2,k_max+2);
	u_pred_pred = allocate_array_of_floats(i_max+2,j_max+2,k_max+2);
	v_pred_pred = allocate_array_of_floats(i_max+2,j_max+2,k_max+2);
	w_pred_pred = allocate_array_of_floats(i_max+2,j_max+2,k_max+2);
	rho_pred_pred = allocate_array_of_floats(i_max+2,j_max+2,k_max+2);

	return(0);
}

/* 
 *	free up allocated memory
 */

int
cleanup_memory()
{

	free(geometry[0][0]);
	free(geometry[0]);
	free(geometry);

	cleanup_array(rho); 
	cleanup_array(u); 
	cleanup_array(v);
	cleanup_array(w); 

	cleanup_array(rho_predictor); 
	cleanup_array(u_predictor); 
	cleanup_array(v_predictor);
	cleanup_array(w_predictor); 

	cleanup_array(rho_ave); 
	cleanup_array(u_ave); 
	cleanup_array(v_ave); 
	cleanup_array(w_ave);

	cleanup_array(rho_buf); 
	cleanup_array(u_buf); 
	cleanup_array(v_buf);
	cleanup_array(w_buf); 

	return(0);
}

my_exit()
{
	fflush(fp_log);
	exit(0);
}


//	like save_for_restart but save the predictors instead
//
int
save_predictor()
{
	int i,j,k;
	FILE *fp_map_restart;
	FILE *fp_t_restart;
	char tmp[300],tmp2[300],mes[400];
	static int first_time = YES;

	sprintf(tmp,"%s/%s.restart_maps.dat",scratch_directory,results_directory);

// before saving the latest maps, back up the previous restart info, just in case 
// the program stops in the middle of saving this stuff
// make some small changes here (10-28-12) to have better safety
	if(first_time == NO) {
		sprintf(tmp2,"%s/%s.backup_restart_maps",scratch_directory,results_directory);
		sprintf(mes,"cp %s %s\n",tmp,tmp2); 
		system(mes);
	}

	fp_map_restart = fopen(tmp,"w");

	sprintf(tmp,"%s/t_restart",results_directory_full_path);

// also save the the previous restart time
	if(first_time == NO) {
		sprintf(tmp2,"%s/backup_t_restart.dat",results_directory_full_path);
		sprintf(mes,"cp %s %s\n",tmp,tmp2); 
		system(mes);
	}

	fp_t_restart = fopen(tmp,"w");

	fprintf(fp_t_restart,"%g\n",t);
	for(i = 0; i <= i_max; i++) {
		for(j = 0; j <= j_max; j++) {
			for(k = 0; k <= k_max; k++) {
				fprintf(fp_map_restart,"%d\t%d\t%d\t%g\t%g\t%g\t%g\n",i,j,k,
					rho_predictor[i][j][k],u_predictor[i][j][k],v_predictor[i][j][k],w_predictor[i][j][k]);
			}
		}
	}

	fclose(fp_t_restart);
	fclose(fp_map_restart);
	first_time = NO;

	return(0);
}

/*
 * 	flag = NOT_STARTED or STARTED
 */
int
find_ghost_sites(int flag)
{
       	int i,j,k,k_0;
        double i_lead[2],i_trail[2];

	k_0 = (k_lip_region_min + k_lip_region_max) / 2;

        for(j = j_corner[LEFT]; j <= j_center[LEFT][CURRENT]+j_width[LEFT]+dj_center[LEFT][CURRENT]+1; j++) {
                i_lead[LEFT] = i_leading_edge(LEFT,j);
                i_trail[LEFT] = i_trailing_edge(LEFT,j);

if(flag == NOT_STARTED) {
fprintf(fp_log,"j %d\ti_pivot / width %d / %g ilead / trail  %g / %g\n",j,i_pivot[LEFT],i_width[LEFT],i_lead[LEFT],i_trail[LEFT]);
}

                for(i = i_lead[LEFT] - 2; i <= i_trail[LEFT] + 2; i++) {
                        if(((geometry[i][j][k_0] == LEFT_LIP) && (geometry[i-1][j][k_0] == OPEN))
                                 || ((geometry[i][j][k_0] == LEFT_LIP) && (geometry[i+1][j][k_0] == OPEN))
                                 || ((geometry[i][j][k_0] == LEFT_LIP) && (geometry[i][j-1][k_0] == OPEN))
                                 || ((geometry[i][j][k_0] == LEFT_LIP) && (geometry[i][j+1][k_0] == OPEN))) {

				for(k = k_lip_region_min; k <= k_lip_region_max; k++) {
                                       	geometry[i][j][k] = GHOST;
				}
                        }
                        else if(((geometry[i][j][k_0] == TOUCH) && (geometry[i-1][j][k_0] == OPEN))
                                 || ((geometry[i][j][k_0] == TOUCH) && (geometry[i+1][j][k_0] == OPEN))
                                 || ((geometry[i][j][k_0] == TOUCH) && (geometry[i][j-1][k_0] == OPEN))
                                 || ((geometry[i][j][k_0] == TOUCH) && (geometry[i][j+1][k_0] == OPEN))) {

				for(k = k_lip_region_min; k <= k_lip_region_max; k++) {
                                       	geometry[i][j][k] = GHOST;
				}
                        }
                }
        }

// next do right side
        for(j = j_corner[RIGHT]; j >= j_center[RIGHT][CURRENT]-j_width[RIGHT]+dj_center[RIGHT][CURRENT]-1;j--) {
                i_lead[RIGHT] = i_leading_edge(RIGHT,j);
                i_trail[RIGHT] = i_trailing_edge(RIGHT,j);

                for(i = i_lead[RIGHT] - 2; i <= i_trail[RIGHT] + 2; i++) {
                        if(((geometry[i][j][k_0] == RIGHT_LIP) && (geometry[i-1][j][k_0] == OPEN)) 
                                 || ((geometry[i][j][k_0] == RIGHT_LIP) && (geometry[i+1][j][k_0] == OPEN))
                                 || ((geometry[i][j][k_0] == RIGHT_LIP) && (geometry[i][j-1][k_0] == OPEN))
                                 || ((geometry[i][j][k_0] == RIGHT_LIP) && (geometry[i][j+1][k_0] == OPEN))) {

					for(k = k_lip_region_min; k <= k_lip_region_max; k++) {
                                        	geometry[i][j][k] = GHOST;
					}
                        }
                        else if(((geometry[i][j][k_0] == TOUCH) && (geometry[i-1][j][k_0] == OPEN)) 
                                 || ((geometry[i][j][k_0] == TOUCH) && (geometry[i+1][j][k_0] == OPEN))
                                 || ((geometry[i][j][k_0] == TOUCH) && (geometry[i][j-1][k_0] == OPEN))
                                 || ((geometry[i][j][k_0] == TOUCH) && (geometry[i][j+1][k_0] == OPEN))) {

					for(k = k_lip_region_min; k <= k_lip_region_max; k++) {
                                        	geometry[i][j][k] = GHOST;
					}
                        }
                }
        }

	return(0);
}

double
i_leading_edge(int flag, int j)
{
        int i;
        int delta_j;
        double di_dj;
        double edge;

        if(flag == LEFT) {
                delta_j = j - j_pivot[LEFT];
                di_dj = di_center[LEFT][CURRENT] / (j_width[LEFT] + dj_center[LEFT][CURRENT]);
                edge = i_corner[LEFT] + delta_j*di_dj;
        }
        else {
                delta_j = j - j_pivot[RIGHT];
                di_dj = -di_center[RIGHT][CURRENT] / (j_width[RIGHT] - dj_center[RIGHT][CURRENT]);
                edge = i_corner[RIGHT] + delta_j*di_dj;
        }

        return(edge);
}

double
i_trailing_edge(int flag, int j)
{
        int i;
        int delta_j;
        double di_dj;
        double edge;

        if(flag == LEFT) {
                delta_j = j - j_pivot[LEFT];
                di_dj = di_center[LEFT][CURRENT] / (j_width[LEFT] + dj_center[LEFT][CURRENT]);

                edge = i_corner[LEFT] + 2*i_width[LEFT] + delta_j*di_dj;
        }
        else {
                delta_j = j - j_pivot[RIGHT];
                di_dj = -di_center[RIGHT][CURRENT] / (j_width[RIGHT] - dj_center[RIGHT][CURRENT]);
                edge = i_corner[RIGHT] + 2*i_width[RIGHT] + delta_j*di_dj;
 	}

        return(edge);
}

int
nearest_int(double n)
{
        int i;

        return((int)round(n));
}

int
display_lip_region(char *s)
{
	int i,j,k,k_0;
	int j_edge[2];

	fprintf(fp_log,"\n%s\n",s);

fprintf(fp_log,"lip_opening actual/min %g / %g\tlip_width_left actual/min %g / %g\tlip_width_right actual/min %g / %g\n",lip_opening,lip_opening_min,lip_thickness[LEFT],lip_thickness_min,lip_thickness[RIGHT],lip_thickness_min);

fprintf(fp_log,"left i: corner %d\torigin %g\tcenter %g\tdi %g\ti_pivot %d  i_width %g\n",i_corner[LEFT],i_origin[LEFT],i_center[LEFT][CURRENT],di_center[LEFT][CURRENT],i_pivot[LEFT],i_width[LEFT]);

j_edge[LEFT] = j_center[LEFT][CURRENT] + j_width[LEFT] + dj_center[LEFT][CURRENT];
fprintf(fp_log,"left j: corner %d\torigin %g\tcenter %g\tdj %g\tj_edge %d  j_width %g\n",j_corner[LEFT],j_origin[LEFT],j_center[LEFT][CURRENT],dj_center[LEFT][CURRENT],j_edge[LEFT],j_width[LEFT]);

fprintf(fp_log,"right i: corner %d\torigin %g\tcenter %g\tdi %g\ti_pivot %d  i_width %g\n",i_corner[RIGHT],i_origin[RIGHT],i_center[RIGHT][CURRENT],di_center[RIGHT][CURRENT],i_pivot[RIGHT],i_width[RIGHT]);

j_edge[RIGHT] = j_center[RIGHT][CURRENT] - j_width[RIGHT] + dj_center[RIGHT][CURRENT]+1;
fprintf(fp_log,"right j: corner %d\torigin %g\tcenter %g\tdj %g\tj_edge %d  j_width %g\n",j_corner[RIGHT],j_origin[RIGHT],j_center[RIGHT][CURRENT],dj_center[RIGHT][CURRENT],j_edge[RIGHT],j_width[RIGHT]);

// for(k = k_lip_region_min; k <= k_lip_region_max; k++) {
   k = (k_lip_region_max + k_lip_region_min) / 2;
   fprintf(fp_log,"k = %d\n",k);
        for(i = i_lip_region_min - 2; i <= i_lip_region_max + 2; i++) {
                fprintf(fp_log,"%d\t",i);
                for(j = j_lip_region_min - 2; j <= j_lip_region_max + 2; j++) {
                        if((i == i_pivot[LEFT]) && (j == j_pivot[LEFT])) {
                                fprintf(fp_log,"P");
                        }
                        else if((i == i_pivot[RIGHT]) && (j == j_pivot[RIGHT])) {
                                fprintf(fp_log,"P");
                        }
                        else if((i == (int)i_center[LEFT][CURRENT]) && (j == (int)j_center[LEFT][CURRENT])) {
                                fprintf(fp_log,"C");
                        }
                        else if((i == (int)i_center[RIGHT][CURRENT]) && (j == (int)j_center[RIGHT][CURRENT])) {
                                fprintf(fp_log,"C");
                        }
                        else if((i == (int)i_origin[LEFT]) && (j == (int)j_origin[LEFT])) {
                                fprintf(fp_log,"O");
                        }
                        else if((i == (int)i_origin[RIGHT]) && (j == (int)j_origin[RIGHT])) {
                                fprintf(fp_log,"O");
                        }
                        else {
                                if(geometry[i][j][k] == LEFT_LIP) fprintf(fp_log,"L");
                                if(geometry[i][j][k] == RIGHT_LIP) fprintf(fp_log,"R");
                                if(geometry[i][j][k] == OPEN) fprintf(fp_log,".");
                                if(geometry[i][j][k] == SOLID) fprintf(fp_log,"X");
                                if(geometry[i][j][k] == GHOST) fprintf(fp_log,"G");
                                if(geometry[i][j][k] == TOUCH) fprintf(fp_log,"T");
                        }
                }
                fprintf(fp_log,"\n");
        }
	fprintf(fp_log,"\n");

	return(0);
}

int
display_cell_values(char *s)
{
	int i,j,k,k_0;

	fprintf(fp_log,"\n%s\n",s);
        k = (k_lip_region_max + k_lip_region_min) / 2;
	fprintf(fp_log,"k = %d\n",k);
        for(i = i_lip_region_min; i <= i_lip_region_max; i++) {
                fprintf(fp_log,"%d:  ",i);
                for(j = j_lip_region_min - 2; j <= j_lip_region_max + 2; j++) {
			if((geometry[i][j][k] == LEFT_LIP)||(geometry[i][j][k] == RIGHT_LIP)||
					(geometry[i][j][k] == GHOST)) {
				fprintf(fp_log,"%1.2f  ",site_weight[i][j][k]);
			}
			else {
				fprintf(fp_log,"      ");
			}
                }
                fprintf(fp_log,"\n");
        }
	fprintf(fp_log,"\n");
//   }

	return(0);
}

// read in data for lip mass and stiffness
int
init_lip_data()
{
	FILE *fp;
	char tmp[200],mes[200],flag[100],flag2[100],flag3[100],flag4[100];

	strcpy(tmp,"lip_data.dat");
	fp = fopen(tmp,"r");
	if(fp == NULL) {
		fprintf(fp_log,"can't open %s for lip data\n",tmp);
		(void)exit(0);
	}
	
/* put a copy of lip_data.dat into results directory */
	sprintf(mes,"cp %s %s/",tmp,results_directory_full_path);
	system(mes);

	while(1) {
		if(fgets(tmp,100,fp) == NULL) {
			fprintf(stderr, "error in reading run data file\n");
			fprintf(fp_log, "error in reading run data file\n");
			(void)exit(0);
		}
		if(tmp[0] == '#') break;
	}

	fgets(tmp,100,fp);
	sscanf(tmp,"%lf",&f_lip);
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf",&q_lip);
		// next do lip masses - these can be different (if two values are on the line
		//	in the data file) or the same (if there is only one value on the line)
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf %lf",&(m_lip[LEFT]),&(m_lip[RIGHT]));
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf %lf %lf %lf",&(k_lip_x[LEFT]),&(k_lip_y[LEFT]),&(k_lip_x[RIGHT]),&(k_lip_y[RIGHT]));
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf %lf",&z_lip_real,&z_lip_imag);
	fgets(tmp,100,fp);
	sscanf(tmp,"%s",flag);
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf %s",&lip_opening_min,flag2);
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf %s",&lip_thickness_min,flag3);
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf",&k_lip_touch);
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf",&lip_touch_exponent);
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf",&k_lip_angle);
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf",&theta_lip_min);
	fgets(tmp,100,fp);
	sscanf(tmp,"%lf %s",&lip_delta_x_max,flag4);

	if(flag2[0] == 'y') {
		lip_touch_flag = YES;
	}
	else {
		lip_touch_flag = NO;
	}

	if(flag3[0] == 'y') {
		lip_thickness_flag = YES;
	}
	else {
		lip_thickness_flag = NO;
	}

	if(flag4[0] == 'y') {
		lip_dx_max_flag = YES;
	}
	else {
		lip_dx_max_flag = NO;
	}

	if(lip_touch_flag != lip_thickness_flag) {
		fprintf(fp_log,"lip touch and thickness flags should be the same - error\n");
		exit(0);
	}

	z_lip_real_norm = z_lip_real / (c_s * c_s);
	z_lip_imag_norm = z_lip_imag / (c_s * c_s);
	z_lip_1_2_plus = z_lip_real_norm + (z_lip_imag_norm / dt); 
	z_lip_imag_prime = z_lip_imag_norm/dt / z_lip_1_2_plus;	// need to check this

	fprintf(fp_log,"lip data:\n");
	fprintf(fp_log,"f_lip = %g\tq_lip = %g\nm_lip(left) = %g\tm_lip(right) = %g\nLEFT: k_lip(x) = %g\tk_lip(y) = %g\tRIGHT:k_lip(x) = %g\tk_lip(y) = %g\nz_real/z_imag = %g / %g\n",
		f_lip,q_lip,m_lip[LEFT],m_lip[RIGHT],k_lip_x[LEFT],k_lip_y[LEFT],k_lip_x[RIGHT],k_lip_y[RIGHT],z_lip_real,z_lip_imag);
	if(strcmp(flag,"yes") == 0) {
		lip_model_flag = YES;
		fprintf(fp_log,"USING my two spring lip model:\n");
	}
	else if(strcmp(flag,"adachi") == 0) {
		lip_model_flag = ADACHI;
		fprintf(fp_log,"USING adachi swinging lip model:\n");
	}
	else {
		lip_model_flag = NO;
		fprintf(fp_log,"NOT using swinging lip model:\n");	// not currently implemented
	}

	if(lip_touch_flag == YES) {
		fprintf(fp_log,"lips are ALLOWED to touch\n");
	}
	else {
		fprintf(fp_log,"lips are NOT ALLOWED to touch\n");
	}

	if(lip_thickness_flag == YES) {
		fprintf(fp_log,"lip thicknesses are not allowed to be less than %g\n",lip_thickness_min);
	}
	else {
		fprintf(fp_log,"lip thickness is not limited to any minimum value\n");
	}

	if(lip_dx_max_flag == YES) {
		fprintf(fp_log,"lip dx is limited to around %g\n",lip_delta_x_max);
	}
	else {
		fprintf(fp_log,"lip dx is not limited to any max value\n");
	}

	fprintf(fp_log,"min lip opening = %g grid units\n",lip_opening_min);
	fprintf(fp_log,"min lip width left and right = %g grid units\n",lip_thickness_min);
	fprintf(fp_log,"amp of lip force to prevent touching = %g\texponent = %g \n",k_lip_touch,lip_touch_exponent);
	fprintf(fp_log,"amp of lip force to resist lip from rotating too much e= %g\n",k_lip_angle);
	fprintf(fp_log,"minimum lip angle = %g degrees (angle between lip and side of tube)\n",theta_lip_min);
	theta_lip_min *= 3.14 / 180.0;
	fprintf(fp_log,"minimum lip angle = %g radian (small angle means more rotation)\n",theta_lip_min);

	m_cell = rho_air * dx_grid[i_lip_region_min] * dy_grid[j_lip_region_min] * dz_grid[k_lip_region_min];	// mass of one grid cell

	fprintf(fp_log,"mass of one lip cell = %g\n",m_cell);

	fclose(fp);

	return(0);
}

/*
 * 	calculate new lip positions
 * 	use Verlet method
 * 	keep lip force in doubles lip_force_x[2] and lip_force_y[2]
 */
int
move_lips()
{
        int i_edge[2],j_edge[2];
	double delta_j;
	double delta_spring,f_restore;
	double alpha,beta_x,beta_y;
	double di_sign;
	double theta,f_0,d_0;;
	double j_edge_new;
	double k_effective,k_effective_x;
	double j_edge_interior_double[2],lip_opening_interior;
	double lip_thickness_interior[2];

// deal with left lip first

	alpha = dt * dt / m_lip[LEFT];
	beta_x = sqrt(k_lip_x[LEFT] / m_lip[LEFT]) * dt / (2.0 * q_lip);

	j_edge_interior_double[LEFT] = j_origin[LEFT] + j_width[LEFT] + 2.0*dj_center_interior[LEFT][CURRENT];
	j_edge_interior_double[RIGHT] = j_origin[RIGHT] - j_width[RIGHT] + 2.0*dj_center_interior[RIGHT][CURRENT];

	lip_thickness_interior[LEFT] = j_edge_interior_double[LEFT] - j_pivot[LEFT];
	lip_thickness_interior[RIGHT] = j_pivot[RIGHT] - j_edge_interior_double[RIGHT];

	lip_opening_interior = (j_origin[RIGHT] - j_width[RIGHT] + 2.0*dj_center_interior[RIGHT][CURRENT])
        	- (j_origin[LEFT] + j_width[LEFT] + 2.0*dj_center_interior[LEFT][CURRENT]);

	k_effective = k_lip_y[LEFT];
	beta_y = sqrt(k_lip_y[LEFT] / m_lip[LEFT]) * dt / (2.0 * q_lip);
	if((lip_opening_interior <= lip_opening_min) || (lip_thickness_interior[LEFT] <= lip_thickness_min)) {
		k_effective = k_lip_touch;
		beta_y = sqrt(k_lip_touch / m_lip[LEFT]) * dt / (2.0 * q_lip);
	}

	k_effective_x = k_lip_x[LEFT];
	beta_x = sqrt(k_lip_x[LEFT] / m_lip[LEFT]) * dt / (2.0 * q_lip);
	if((di_center_interior[LEFT][CURRENT] >= lip_delta_x_max) && (lip_dx_max_flag == YES)) {
		k_effective_x = k_lip_touch;		// use same k_lip_touch here as for y direction
		beta_x = sqrt(k_lip_touch / m_lip[LEFT]) * dt / (2.0 * q_lip);
	}

//	lip_force_x[LEFT] = -k_lip_x[LEFT] * di_center[LEFT][CURRENT] - f_pressure_x[LEFT] / dx_grid[i_lip_region_min];
	lip_force_x[LEFT] = -k_effective_x * di_center_interior[LEFT][CURRENT] - f_pressure_x[LEFT] / dx_grid[i_lip_region_min];
								// factor of dx_grid to allow for conversion
								// between di and real space units
	lip_force_y[LEFT] = -k_effective * dj_center_interior[LEFT][CURRENT] - f_pressure_y[LEFT] / dy_grid[j_lip_region_min];

//	di_center[LEFT][NEW] = (1.0/(1.0+beta_x))*
//		(2.0*di_center[LEFT][CURRENT] + (-1.0+beta_x)*di_center[LEFT][OLD] + alpha*lip_force_x[LEFT]);
	di_center_interior[LEFT][NEW] = (1.0/(1.0+beta_x))*
		(2.0*di_center_interior[LEFT][CURRENT] + (-1.0+beta_x)*di_center_interior[LEFT][OLD] + alpha*lip_force_x[LEFT]);
	dj_center_interior[LEFT][NEW] = (1.0/(1.0+beta_y))*
		(2.0*dj_center_interior[LEFT][CURRENT] + (-1.0+beta_y)*dj_center_interior[LEFT][OLD] + alpha*lip_force_y[LEFT]);

// now deal with right lip

	alpha = dt * dt / m_lip[RIGHT];
	beta_x = sqrt(k_lip_x[LEFT] / m_lip[RIGHT]) * dt / (2.0 * q_lip);

	k_effective = k_lip_y[RIGHT];
	beta_y = sqrt(k_lip_y[RIGHT] / m_lip[RIGHT]) * dt / (2.0 * q_lip);
	if((lip_opening_interior <= lip_opening_min) || (lip_thickness_interior[RIGHT] <= lip_thickness_min)) {
		k_effective = k_lip_touch;
		beta_y = sqrt(k_lip_touch / m_lip[RIGHT]) * dt / (2.0 * q_lip);
	}

	k_effective_x = k_lip_x[RIGHT];
	beta_x = sqrt(k_lip_x[RIGHT] / m_lip[RIGHT]) * dt / (2.0 * q_lip);
	if((di_center_interior[RIGHT][CURRENT] > lip_delta_x_max) && (lip_dx_max_flag == YES)) {
		k_effective_x = k_lip_touch;
		beta_x = sqrt(k_lip_touch / m_lip[RIGHT]) * dt / (2.0 * q_lip);
	}

//	lip_force_x[RIGHT] = -k_lip_x[LEFT] * di_center[RIGHT][CURRENT] - f_pressure_x[RIGHT] / dx_grid[i_lip_region_min];
	lip_force_x[RIGHT] = -k_effective_x * di_center_interior[RIGHT][CURRENT] - f_pressure_x[RIGHT] / dx_grid[i_lip_region_min];
								// factor of dx_grid to allow for conversion
								// between di and real space units
	lip_force_y[RIGHT] = -k_effective * dj_center_interior[RIGHT][CURRENT] - f_pressure_y[RIGHT] / dy_grid[j_lip_region_min];

//	di_center[RIGHT][NEW] = (1.0/(1.0+beta_x))*
//		(2.0*di_center[RIGHT][CURRENT] + (-1.0+beta_x)*di_center[RIGHT][OLD] + alpha*lip_force_x[RIGHT]);
	di_center_interior[RIGHT][NEW] = (1.0/(1.0+beta_x))*
		(2.0*di_center_interior[RIGHT][CURRENT] + (-1.0+beta_x)*di_center_interior[RIGHT][OLD] + alpha*lip_force_x[RIGHT]);
	dj_center_interior[RIGHT][NEW] = (1.0/(1.0+beta_y))*
		(2.0*dj_center_interior[RIGHT][CURRENT] + (-1.0+beta_y)*dj_center_interior[RIGHT][OLD] + alpha*lip_force_y[RIGHT]);


//	di_center[LEFT][OLD] = di_center[LEFT][CURRENT];
//	di_center[LEFT][CURRENT] = di_center[LEFT][NEW];
	di_center_interior[LEFT][OLD] = di_center_interior[LEFT][CURRENT];
	di_center_interior[LEFT][CURRENT] = di_center_interior[LEFT][NEW];
	dj_center_interior[LEFT][OLD] = dj_center_interior[LEFT][CURRENT];
	dj_center_interior[LEFT][CURRENT] = dj_center_interior[LEFT][NEW];

//	di_center[RIGHT][OLD] = di_center[RIGHT][CURRENT];
//	di_center[RIGHT][CURRENT] = di_center[RIGHT][NEW];
	di_center_interior[RIGHT][OLD] = di_center_interior[RIGHT][CURRENT];
	di_center_interior[RIGHT][CURRENT] = di_center_interior[RIGHT][NEW];
	dj_center_interior[RIGHT][OLD] = dj_center_interior[RIGHT][CURRENT];
	dj_center_interior[RIGHT][CURRENT] = dj_center_interior[RIGHT][NEW];

	lip_opening_interior = (j_origin[RIGHT] - j_width[RIGHT] + 2.0*dj_center_interior[RIGHT][NEW])
	       	- (j_origin[LEFT] + j_width[LEFT] + 2.0*dj_center_interior[LEFT][NEW]);

	j_edge_interior_double[LEFT] = j_origin[LEFT] + j_width[LEFT] + 2.0 * dj_center_interior[LEFT][NEW];
	j_edge_interior_double[RIGHT] = j_origin[RIGHT] - j_width[RIGHT] + 2.0 * dj_center_interior[RIGHT][NEW];

	lip_thickness_interior[LEFT] = j_edge_interior_double[LEFT] - j_pivot[LEFT];
	lip_thickness_interior[RIGHT] = j_pivot[RIGHT] - j_edge_interior_double[RIGHT];

	if((lip_touch_flag == NO) && (lip_thickness_flag == NO)) {
		if((lip_opening_interior > lip_opening_min) && (lip_thickness_interior[LEFT] > lip_thickness_min)
			&& (lip_thickness_interior[RIGHT] > lip_thickness_min)) {
			dj_center[LEFT][NEW] = dj_center_interior[LEFT][NEW];
			dj_center[RIGHT][NEW] = dj_center_interior[RIGHT][NEW];
		}
		else if((lip_opening_interior > lip_opening_min) && (lip_thickness_interior[LEFT] > lip_thickness_min)
			&& (lip_thickness_interior[RIGHT] <= lip_thickness_min)) {
			dj_center[LEFT][NEW] = dj_center_interior[LEFT][NEW];
			dj_center[RIGHT][NEW] = (lip_thickness_min - j_pivot[RIGHT] + (j_origin[RIGHT]-j_width[RIGHT]))/2.0;
		}
		else if((lip_opening_interior > lip_opening_min) && (lip_thickness_interior[LEFT] <= lip_thickness_min)
			&& (lip_thickness_interior[RIGHT] > lip_thickness_min)) {
			dj_center[LEFT][NEW] = (lip_thickness_min + j_pivot[LEFT] - (j_origin[LEFT]+j_width[LEFT]))/2.0;
			dj_center[RIGHT][NEW] = dj_center_interior[RIGHT][NEW];
		}
		else if((lip_opening_interior > lip_opening_min) && (lip_thickness_interior[LEFT] <= lip_thickness_min)
			&& (lip_thickness_interior[RIGHT] <= lip_thickness_min)) {
			dj_center[LEFT][NEW] = (lip_thickness_min + j_pivot[LEFT] - (j_origin[LEFT]+j_width[LEFT]))/2.0;
			dj_center[RIGHT][NEW] = (lip_thickness_min - j_pivot[RIGHT] + (j_origin[RIGHT]-j_width[RIGHT]))/2.0;
		}
		else if(lip_opening_interior <= lip_opening_min) {
			j_edge_new = (j_edge_interior_double[RIGHT] + j_edge_interior_double[LEFT]) / 2.0;
			dj_center[LEFT][NEW] = ((j_edge_new -(j_origin[LEFT]+j_width[LEFT])) / 2.0) - lip_opening_min / 4.0;
			dj_center[RIGHT][NEW] = ((j_edge_new -(j_origin[RIGHT]-j_width[RIGHT])) / 2.0) + lip_opening_min / 4.0;
		}
	}
	else if((lip_touch_flag == YES) && (lip_thickness_flag == YES)) {
		if(lip_opening_interior <= lip_opening_min) {
			// lips at at min allowed spacing -- assume they meet halfway between previous edges
			// set new vals of dj_center so that lip_opening is lip_opening_min which should be zero
			j_edge_new = (j_edge_interior_double[RIGHT] + j_edge_interior_double[LEFT]) / 2.0;
			dj_center[LEFT][NEW] = ((j_edge_new -(j_origin[LEFT]+j_width[LEFT])) / 2.0) - lip_opening_min/4.0;
			dj_center[RIGHT][NEW] = ((j_edge_new -(j_origin[RIGHT]-j_width[RIGHT])) / 2.0) + lip_opening_min/4.0;
		}
		else if((lip_thickness_interior[LEFT] > lip_thickness_min) && (lip_thickness_interior[RIGHT] > lip_thickness_min)) {
			dj_center[LEFT][NEW] = dj_center_interior[LEFT][NEW];
			dj_center[RIGHT][NEW] = dj_center_interior[RIGHT][NEW];
		}
// work to do here
		else if((lip_thickness_interior[LEFT] <= lip_thickness_min) && (lip_thickness_interior[RIGHT] > lip_thickness_min)) {
			dj_center[LEFT][NEW] = (lip_thickness_min + j_pivot[LEFT] - (j_origin[LEFT]+j_width[LEFT]))/2.0;
			dj_center[RIGHT][NEW] = dj_center_interior[RIGHT][NEW];
		}
		else if((lip_thickness_interior[LEFT] > lip_thickness_min) && (lip_thickness_interior[RIGHT] <= lip_thickness_min)) {
			dj_center[LEFT][NEW] = dj_center_interior[LEFT][NEW];
			dj_center[RIGHT][NEW] = (-lip_thickness_min + j_pivot[RIGHT] - (j_origin[RIGHT]-j_width[RIGHT]))/2.0;
		}
		else if((lip_thickness_interior[LEFT] <= lip_thickness_min) && (lip_thickness_interior[RIGHT] <= lip_thickness_min)) {
			dj_center[LEFT][NEW] = (lip_thickness_min + j_pivot[LEFT] - (j_origin[LEFT]+j_width[LEFT]))/2.0;
			dj_center[RIGHT][NEW] = (-lip_thickness_min + j_pivot[RIGHT] - (j_origin[RIGHT]-j_width[RIGHT]))/2.0;
		}
	}

	if((di_center_interior[LEFT][CURRENT] >= lip_delta_x_max) && (lip_dx_max_flag == YES)) {
		di_center[LEFT][NEW] = lip_delta_x_max;
	}
	else if((di_center_interior[LEFT][CURRENT] <= -lip_delta_x_max) && (lip_dx_max_flag == YES)) {
		di_center[LEFT][NEW] = -lip_delta_x_max;
	}
	else {
		di_center[LEFT][NEW] = di_center_interior[LEFT][NEW];
	}

	if((di_center_interior[RIGHT][CURRENT] >= lip_delta_x_max) && (lip_dx_max_flag == YES)) {
		di_center[RIGHT][NEW] = lip_delta_x_max;
	}
	else if((di_center_interior[RIGHT][CURRENT] <= -lip_delta_x_max) && (lip_dx_max_flag == YES)) {
		di_center[RIGHT][NEW] = -lip_delta_x_max;
	}
	else {
		di_center[RIGHT][NEW] = di_center_interior[RIGHT][NEW];
	}

	dj_center[LEFT][OLD] = dj_center[LEFT][CURRENT];
	dj_center[LEFT][CURRENT] = dj_center[LEFT][NEW];
	di_center[LEFT][OLD] = di_center[LEFT][CURRENT];
	di_center[LEFT][CURRENT] = di_center[LEFT][NEW];

	dj_center[RIGHT][OLD] = dj_center[RIGHT][CURRENT];
	dj_center[RIGHT][CURRENT] = dj_center[RIGHT][NEW];
	di_center[RIGHT][OLD] = di_center[RIGHT][CURRENT];
	di_center[RIGHT][CURRENT] = di_center[RIGHT][NEW];

	i_center[LEFT][OLD] = i_center[LEFT][CURRENT];
	j_center[LEFT][OLD] = j_center[LEFT][CURRENT];
	i_center[RIGHT][OLD] = i_center[RIGHT][CURRENT];
	j_center[RIGHT][OLD] = j_center[RIGHT][CURRENT];

	i_center[LEFT][CURRENT] = i_origin[LEFT] + di_center[LEFT][CURRENT];
	j_center[LEFT][CURRENT] = j_origin[LEFT] + dj_center[LEFT][CURRENT];
	i_center[RIGHT][CURRENT] = i_origin[RIGHT] + di_center[RIGHT][CURRENT];
	j_center[RIGHT][CURRENT] = j_origin[RIGHT] + dj_center[RIGHT][CURRENT];

	return(0);
}

/*
 * 	using site weights (level sets) according to Pederzani algorithm
 *
 *	do some diagnostics with variables u_lip_upstream_ave,v_lip_upstream_ave,u_predictor_upstream_ave,v_predictor_upstream_ave;
 *	f_pres_upstream_ave,f_pres_downstream_ave,f_pres_y_ave;
 */
/*
int
update_velocity_on_lip_surfaces()
{
	int i,j,k,k0;
	int lip_flag;
	double u_lip,v_lip;
	int n;

	k0 = (k_lip_region_min + k_lip_region_max) / 2;
	n = 0;
	u_predictor_upstream_ave = v_predictor_upstream_ave = u_lip_upstream_ave = v_lip_upstream_ave = 0.0;	// for diagnostics
	f_pres_upstream_ave = f_pres_y_ave = 0.0;

	f_pressure_x[LEFT] = f_pressure_x[RIGHT] = f_pressure_y[LEFT] = f_pressure_y[RIGHT] = 0.0;
	for(i = i_lip_region_min; i <= i_lip_region_max; i++) {	
		for(j = j_lip_region_min; j <= j_lip_region_max; j++) {	
			for(k = k_lip_region_min; k <= k_lip_region_max; k++) {	
				if((lip_flag = which_side(i,j)) == LEFT) {
				   u_lip = ((j-j_pivot[LEFT])/(j_center[LEFT][CURRENT] - j_pivot[LEFT])) 
					* dx_grid[i]*(di_center[LEFT][CURRENT]-di_center[LEFT][OLD])/dt;
				   v_lip = ((j-j_pivot[LEFT])/(j_center[LEFT][CURRENT] - j_pivot[LEFT])) 
				   	* dy_grid[j]*(dj_center[LEFT][CURRENT]-dj_center[LEFT][OLD])/dt;
				}
				else {
				   u_lip = ((j_pivot[RIGHT]-j)/(-j_center[RIGHT][CURRENT]+j_pivot[RIGHT])) 
					* dx_grid[i]*(di_center[RIGHT][CURRENT]-di_center[RIGHT][OLD])/dt;
				   v_lip = ((j_pivot[RIGHT]-j)/(-j_center[RIGHT][CURRENT]+j_pivot[RIGHT])) 
				   	* dy_grid[j]*(dj_center[RIGHT][CURRENT]-dj_center[RIGHT][OLD])/dt;
				}
				if(geometry[i][j][k] == GHOST) {
					u_pred_pred[i][j][k] = (1.0-site_weight[i][j][k])*u_predictor[i][j][k]
						+ site_weight[i][j][k]*u_lip;
					f_pressure_x[lip_flag] += site_weight[i][j][k]*(u_lip-u_predictor[i][j][k])
						* (1-site_weight[i][j][k])*(m_cell/dt);
					v_pred_pred[i][j][k] = (1.0-site_weight[i][j][k])*v_predictor[i][j][k]
						+ site_weight[i][j][k]*v_lip;
					f_pressure_y[lip_flag] += site_weight[i][j][k]*(v_lip-v_predictor[i][j][k])
						* (1-site_weight[i][j][k])*(m_cell/dt);
					w_pred_pred[i][j][k] = (1.0-site_weight[i][j][k])*w_predictor[i][j][k];
				}
				else if((geometry[i][j][k] == LEFT_LIP) || (geometry[i][j][k] == RIGHT_LIP)) {
					u_pred_pred[i][j][k] = u_lip;
					v_pred_pred[i][j][k] = v_lip;
					w_pred_pred[i][j][k] = 0.0; 
					rho_predictor[i][j][k] = 0.0; 
				}
			}
		}
	}
	return(0);
}
*/

save_lip_predictors()
{
	int i,j,k;

#ifdef CLUSTER
#pragma omp collapse(3)
#pragma omp parallel for shared(u,v,w,rho,u_pred_pred,v_pred_pred,w_pred_pred,rho_predictor)  private(i,j,k) 
#endif

	for(i = i_lip_region_min; i <= i_lip_region_max; i++) {	
		for(j = j_lip_region_min; j <= j_lip_region_max; j++) {	
			for(k = k_lip_region_min; k <= k_lip_region_max; k++) {	
				if((geometry[i][j][k] == GHOST) ||
					(geometry[i][j][k] == LEFT_LIP) ||
					(geometry[i][j][k] == RIGHT_LIP)) {
						u[i][j][k] = u_pred_pred[i][j][k];
						v[i][j][k] = v_pred_pred[i][j][k];
						w[i][j][k] = w_pred_pred[i][j][k];
 						rho[i][j][k] = rho_pred_pred[i][j][k];
				}
			}
		}
	}

	return(0);
}

save_lip_predictors2()
{
	int i,j,k;

#ifdef CLUSTER
#pragma omp collapse(3)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif

	for(i = i_lip_region_min; i <= i_lip_region_max; i++) {	
		for(j = j_lip_region_min; j <= j_lip_region_max; j++) {	
			for(k = k_lip_region_min; k <= k_lip_region_max; k++) {	
				if((geometry[i][j][k] == GHOST) || (geometry[i][j][k] == LEFT_LIP) || (geometry[i][j][k] == RIGHT_LIP)) {
					u[i][j][k] = u_predictor[i][j][k];
					v[i][j][k] = v_predictor[i][j][k];
					w[i][j][k] = w_predictor[i][j][k];
					rho[i][j][k] = rho_predictor[i][j][k];
				}
			}
		}
	}

	return(0);
}
			
/*
 * 	after moving lips need to relabel lip and ghost sites
 * 	do the lip sites here and then mark ghost sites in a different routine next
 */
remark_lip_sites()
{
	int i,j,k;
	double i_lead[2],i_trail[2],j_edge[2];

        j_edge[LEFT] = j_center[LEFT][CURRENT] + j_width[LEFT] + dj_center[LEFT][CURRENT];

        for(j = j_corner[LEFT]; j <= j_edge[LEFT]; j++) {
                i_lead[LEFT] = i_leading_edge(LEFT,j) + 1;
                i_trail[LEFT] = i_trailing_edge(LEFT,j);
                for(i = i_lead[LEFT]; i <= i_trail[LEFT]; i++) {
			for(k = k_lip_region_min; k <= k_lip_region_max; k++) {
                        	geometry[i][j][k] = LEFT_LIP;
			}
                }
        }

	j_edge[RIGHT] = j_center[RIGHT][CURRENT] - j_width[RIGHT] + dj_center[RIGHT][CURRENT]+1;

        for(j = j_corner[RIGHT]; j >= j_edge[RIGHT]; j--) {
                i_lead[RIGHT] = i_leading_edge(RIGHT,j) + 1;
                i_trail[RIGHT] = i_trailing_edge(RIGHT,j);
                for(i = i_lead[RIGHT]; i <= i_trail[RIGHT]; i++) {
			for(k = k_lip_region_min; k <= k_lip_region_max; k++) {
                        	geometry[i][j][k] = RIGHT_LIP;
			}
                }
        }

	return(0);
}

int
calc_lip_surface_predictors()
{
	int i,j,k;
	double vel_perp,xhat,yhat;

//calc_lip_surface_predictors2();
//return(0);

#ifdef CLUSTER
#pragma omp collapse(3)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif

	for(i = i_lip_region_min; i <= i_lip_region_max; i++) {	
		for(j = j_lip_region_min; j <= j_lip_region_max; j++) {	
			for(k = k_lip_region_min; k <= k_lip_region_max; k++) {	
				if(geometry[i][j][k] == GHOST) {
					xhat = yhat = 0.0;
					rho_predictor[i][j][k] = rho[i][j][k] + artificial_viscosity_on_lips(); 
					if(geometry[i-1][j][k] == OPEN) {
			                        rho_predictor[i][j][k] += 
                   			        -(dt/dx_grid[i-1])*rho_air*(u[i][j][k] - u[i-1][j][k])
		                                -(dt/dx_grid[i-1])*u[i][j][k]*(rho[i][j][k] - rho[i-1][j][k]);
						xhat = -1.0;
					}
					else if(geometry[i+1][j][k] == OPEN) {
			                        rho_predictor[i][j][k] += 
                                		-(dt/dx_grid[i])*rho_air*(u[i+1][j][k] - u[i][j][k])
                                		-(dt/dx_grid[i])*u[i][j][k]*(rho[i+1][j][k] - rho[i][j][k]);
						xhat = 1.0;
					}
					else if(geometry[i][j-1][k] == OPEN) {
                       				rho_predictor[i][j][k] += 
                                		-(dt/dy_grid[j-1])*rho_air*(v[i][j][k] - v[i][j-1][k])
                                		-(dt/dy_grid[j-1])*v[i][j][k]*(rho[i][j][k] - rho[i][j-1][k]);
						yhat = -1.0;
					}
					else if(geometry[i][j+1][k] == OPEN) {
                        			rho_predictor[i][j][k] += 
                                		-(dt/dy_grid[j])*rho_air*(v[i][j+1][k] - v[i][j][k])
                                		-(dt/dy_grid[j])*v[i][j][k]*(rho[i][j+1][k] - rho[i][j][k]);
						yhat = 1.0;
					}
					vel_perp = rho_predictor[i][j][k] / z_lip_1_2_plus;
					u_predictor[i][j][k] = u[i][j][k] * z_lip_2_prime + vel_perp * xhat;
					v_predictor[i][j][k] = v[i][j][k] * z_lip_2_prime + vel_perp * yhat;
					w_predictor[i][j][k] = w[i][j][k] * z_lip_2_prime;
				}
			}
                }
	}

	return(0);
}

int
calc_lip_surface_predictors2()

{
	int i,j,k;
	double viscosity_1,viscosity_2;

	viscosity_1 = viscosity_2 = 0.0;
	if(t >= t_viscosity_start) {
		viscosity_1 = viscosity_1_0;
		viscosity_2 = viscosity_2_0;
	}

#ifdef CLUSTER
#pragma omp collapse(3)
#pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
#endif

	for(i = i_lip_region_min; i <= i_lip_region_max; i++) {	
		for(j = j_lip_region_min; j <= j_lip_region_max; j++) {	
			for(k = k_lip_region_min; k <= k_lip_region_max; k++) {	
				if(geometry[i][j][k] == GHOST) {
				  	rho_predictor[i][j][k] = rho[i][j][k]
					  - (dt/dx_grid[i]) * u[i][j][k] * (rho[i+1][j][k] - rho[i][j][k])
					  - (dt/dx_grid[i]) * rho_air * (u[i+1][j][k] - u[i][j][k])
					  - (dt/dy_grid[j]) * v[i][j][k] * (rho[i][j+1][k] - rho[i][j][k])
					  - (dt/dy_grid[j]) * rho_air * (v[i][j+1][k] - v[i][j][k])
					  - (dt/dz_grid[k]) * w[i][j][k] * (rho[i][j][k+1] - rho[i][j][k])
					  - (dt/dz_grid[k]) * rho_air * (w[i][j][k+1] - w[i][j][k]);
//					  + artificial_viscosity(i,j,k,rho,rho,viscosity_1,viscosity_2);

					  u_predictor[i][j][k] = u[i][j][k] 
					  - (dt/dx_grid[i]) * u[i][j][k] * (u[i+1][j][k] - u[i][j][k])
					  - (dt/dy_grid[j]) * v[i][j][k] * (u[i][j+1][k] - u[i][j][k])
					  - (dt/dz_grid[k]) * w[i][j][k] * (u[i][j][k+1] - u[i][j][k])
					  -(c_s*c_s/rho_air)*(dt/dx_grid[i]) * (rho[i+1][j][k] - rho[i][j][k])
					  +nu*dt*(second_deriv_x(u,i,j,k)+second_deriv_y(u,i,j,k)+second_deriv_z(u,i,j,k));
//					  + artificial_viscosity(i,j,k,u,rho,viscosity_1,viscosity_2);

					  v_predictor[i][j][k] = v[i][j][k] 
					  - (dt/dx_grid[i]) * u[i][j][k] * (v[i+1][j][k] - v[i][j][k])
					  - (dt/dy_grid[j]) * v[i][j][k] * (v[i][j+1][k] - v[i][j][k])
					  - (dt/dz_grid[k]) * w[i][j][k] * (v[i][j][k+1] - v[i][j][k])
					  -(c_s*c_s/rho_air)*(dt/dy_grid[j]) * (rho[i][j+1][k] - rho[i][j][k])
					  +nu*dt*(second_deriv_x(v,i,j,k)+second_deriv_y(v,i,j,k)+second_deriv_z(v,i,j,k));
//					  + artificial_viscosity(i,j,k,v,rho,viscosity_1,viscosity_2);

					  w_predictor[i][j][k] = w[i][j][k] 
					  - (dt/dx_grid[i]) * u[i][j][k] * (w[i+1][j][k] - w[i][j][k])
					  - (dt/dy_grid[j]) * v[i][j][k] * (w[i][j+1][k] - w[i][j][k])
					  - (dt/dz_grid[k]) * w[i][j][k] * (w[i][j][k+1] - w[i][j][k])
					  -(c_s*c_s/rho_air)*(dt/dz_grid[k]) * (rho[i][j][k+1] - rho[i][j][k])
					  +nu*dt*(second_deriv_x(w,i,j,k)+second_deriv_y(w,i,j,k)+second_deriv_z(w,i,j,k));
//					  + artificial_viscosity(i,j,k,w,rho,viscosity_1,viscosity_2);
				}
			}
		}
	}

	return(0);
}

/*
 *     return LEFT or RIGHT depending on which lip the point i,j is on
 */
int
which_side(int i, int j)
{
        int side;
	int k_mid;
        double  jmin[2],jmax[2];

	k_mid = (k_lip_region_min + k_lip_region_max) / 2;

        jmin[LEFT] = j_pivot[LEFT] + 1;
        jmax[LEFT] = j_center[LEFT][CURRENT] + j_width[LEFT] + dj_center[LEFT][CURRENT];

        jmin[RIGHT] = j_center[RIGHT][CURRENT] - j_width[RIGHT] + dj_center[RIGHT][CURRENT];
        jmax[RIGHT] = j_pivot[RIGHT] - 1;

	if(jmin[RIGHT] > jmax[LEFT]) {
        	if((j >= jmin[LEFT]) && (j <= jmax[LEFT])) return(LEFT);
        	if((j >= jmin[RIGHT]) && (j <= jmax[RIGHT])) return(RIGHT);
	}
/*
	else if(geometry[i][j+1][k] == OPEN) {
		return(LEFT);
	}
	else if(geometry[i][j-1][k] == OPEN) {
		return(RIGHT);
	}
*/

        return(-1);
}

double 
artificial_viscosity_on_lips()
{

	return(0.0);
}

int 
nan_check(int n, int *i0, int *j0, int *k0)
{
	int i,j,k;
	int flag;

	flag = NO;

// #ifdef CLUSTER
// #pragma omp collapse(3)
// #pragma omp parallel for shared(u,v,w,rho,u_predictor,v_predictor,w_predictor,rho_predictor)  private(i,j,k) 
// #endif

        for(i = i_lip_region_min-20; i <= i_lip_region_max-1+20; i++) {
                for(j = j_lip_region_min-20; j <= j_lip_region_max-1+20; j++) {
                        for(k = k_lip_region_min-5; k <= k_lip_region_max-1+5; k++) {
                                if((isnan(rho[i][j][k]) != 0) || (isnan(u[i][j][k]) != 0)) {
                                        fprintf(fp_log,"nan at loc %d\t= %g\t%d\t%d\t%d\t\trho/u/v/w = %g/%g/%g/%g\n",n,t,i,j,k,rho[i][j][k],u[i][j][k],v[i][j][k],w[i][j][k]);
                                        fprintf(fp_log,"\tgeom = %d\t%d\t%d\t%d\t%d\t%d\t%d\n",geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k],geometry[i][j][k+1],geometry[i][j][k-1]);
					flag = YES;
					*i0 = i;
					*j0 = j;
					*k0 = k;
                                }
                                if((fabs(rho[i][j][k]) > 1e3) || (fabs(u[i][j][k]) > 1e3)|| (fabs(v[i][j][k]) > 1e3) || (fabs(w[i][j][k]) > 1e3)) {
                                        fprintf(fp_log,"rho or u too big at loc %d\t= %g\t%d\t%d\t%d\t\trho/u/v/w = %g/%g/%g/%g\n",n,t,i,j,k,rho[i][j][k],u[i][j][k],v[i][j][k],w[i][j][k]);
                                        fprintf(fp_log,"\tgeom = %d\t%d\t%d\t%d\t%d\t%d\t%d\n",geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k],geometry[i][j][k+1],geometry[i][j][k-1]);
					flag = YES;
					*i0 = i;
					*j0 = j;
					*k0 = k;
                                }
                                if((isnan(rho_predictor[i][j][k]) != 0) || (isnan(u_predictor[i][j][k]) != 0)) {
                                        fprintf(fp_log,"predictor nan at loc %d\t= %g\t%d\t%d\t%d\t\trho/u/v/w = %g/%g/%g/%g\n",n,t,i,j,k,rho_predictor[i][j][k],u_predictor[i][j][k],v_predictor[i][j][k],w_predictor[i][j][k]);
                                        fprintf(fp_log,"\tgeom = %d\t%d\t%d\t%d\t%d\t%d\t%d\n",geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k],geometry[i][j][k+1],geometry[i][j][k-1]);
					flag = YES;
					*i0 = i;
					*j0 = j;
					*k0 = k;
                                }
                                if((fabs(rho_predictor[i][j][k]) > 1e3) || (fabs(u_predictor[i][j][k]) > 1e3) || (fabs(v_predictor[i][j][k]) > 1e3) || (fabs(w_predictor[i][j][k]) > 1e3)) {
                                        fprintf(fp_log,"predictor too big at loc %d\t= %g\t%d\t%d\t%d\t\trho/u/v/w = %g/%g/%g/%g\n",n,t,i,j,k,rho_predictor[i][j][k],u_predictor[i][j][k],v_predictor[i][j][k],w_predictor[i][j][k]);
                                        fprintf(fp_log,"\tgeom = %d\t%d\t%d\t%d\t%d\t%d\t%d\n",geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k],geometry[i][j][k+1],geometry[i][j][k-1]);
					flag = YES;
					*i0 = i;
					*j0 = j;
					*k0 = k;
                                }
                                if((isnan(u_pred_pred[i][j][k]) != 0) || (isnan(v_pred_pred[i][j][k]) != 0) || (isnan(w_pred_pred[i][j][k]) != 0)) {
                                        fprintf(fp_log,"pred_pred nan at loc %d\t= %g\t%d\t%d\t%d\t\trho/u/v/w = %g/%g/%g/%g\n",n,t,i,j,k,rho_predictor[i][j][k],u_pred_pred[i][j][k],v_pred_pred[i][j][k],w_pred_pred[i][j][k]);
                                        fprintf(fp_log,"\tgeom = %d\t%d\t%d\t%d\t%d\t%d\t%d\n",geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k],geometry[i][j][k+1],geometry[i][j][k-1]);
					flag = YES;
					*i0 = i;
					*j0 = j;
					*k0 = k;
                                }
                                if((fabs(u_pred_pred[i][j][k]) > 1e3) || (fabs(v_pred_pred[i][j][k]) > 1e3) || (fabs(w_pred_pred[i][j][k]) > 1e3)) {
                                        fprintf(fp_log,"pred_pred too big at loc %d\t%d\t%d\t= %g\t%d\t%d\t%d\t\trho/u/v/w = %g/%g/%g/%g\n",n,t,i,j,k,rho_predictor[i][j][k],u_pred_pred[i][j][k],v_pred_pred[i][j][k],w_pred_pred[i][j][k]);
                                        fprintf(fp_log,"\tgeom = %d\t%d\t%d\t%d\t%d\n",geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k],geometry[i][j][k+1],geometry[i][j][k-1]);
					flag = YES;
					*i0 = i;
					*j0 = j;
					*k0 = k;
                                }
                        }
                }
        }

	return(flag);
}

/*
 * 	is the point i,j closer to the leading or trailing edge?
 * 	return LEADING_EDGE, TRAILING_EDGE, or MIDDLE
 */
int
is_closer(int i,int j)
{
	double i_lead,i_trail;
	double j_edge;
	double flag;


	if(which_side(i,j) == LEFT) {
//		j_edge = j_center[LEFT][CURRENT] + j_width[LEFT] + dj_center[LEFT][CURRENT];
// don't check for now if this point is actually on the lip in terms of the i or j coordinate
		i_lead = i_leading_edge(LEFT,j);
		i_trail = i_trailing_edge(LEFT,j);
		if((i - i_lead) < (i_trail - i)) {
			flag = LEADING_EDGE;
		}
		else if((i - i_lead) > (i_trail - i)) {
			flag = TRAILING_EDGE;
		}
		else {
			flag = MIDDLE;
		}
	}	
	else {
		i_lead = i_leading_edge(RIGHT,j);
		i_trail = i_trailing_edge(RIGHT,j);
		if((i - i_lead) < (i_trail - i)) {
			flag = LEADING_EDGE;
		}
		else if((i - i_lead) > (i_trail - i)) {
			flag = TRAILING_EDGE;
		}
		else {
			flag = MIDDLE;
		}
	}

	return(flag);
}
	
/*
 * 	calc weights for each site
 * 	weight = 0 for sites away from the lips
 * 	weight = 1 for sites inside a lip
 * 	weight = between 0 and 1 for sites at edges of a lip
 */
int
calc_site_weights()
{
	int i,j,k,n;
	int closer_to,error_flag;
	double i_lead,i_trail,j_edge,j_sloping_edge;
	double sum,dsum;
	int k_mid;

	error_flag = NO;
	k_mid = (k_lip_region_min + k_lip_region_max) / 2;

        for(i = i_lip_region_min; i <= i_lip_region_max; i++) {
                for(j = j_lip_region_min; j <= j_lip_region_max; j++) {
		   for(k = k_lip_region_min; k <= k_lip_region_max; k++) {
			site_weight[i][j][k] = 0.0;
                        sum = 0.0;
                        if(geometry[i][j][k] == OPEN) {
				sum = 0.0;
			}
                        else if(geometry[i][j][k] == LEFT_LIP) {
				sum = 4.0;
                        }
                        else if(geometry[i][j][k] == RIGHT_LIP) {
				sum = 4.0;
                        }
                        if((geometry[i][j][k] == GHOST) && (which_side(i,j) == LEFT)) {
				sum = 4.0;
                                        i_lead = i_leading_edge(LEFT,j);
                                        i_trail = i_trailing_edge(LEFT,j);
                                        j_edge = j_center[LEFT][CURRENT] + j_width[LEFT] + dj_center[LEFT][CURRENT];
                                        if(geometry[i-1][j][k] == OPEN) {
                                                sum -= dsum = 1 - (i - i_lead);
//if((i == 105) && (j == 84) && (k == k_mid) && (t > 0.01951240)) {
//fprintf(fp_log,"(1)sum / dsum = %g / %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,dsum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
//if((i == 66) && (j == 111) && (k == 180)) {
//fprintf(fp_log,"(1)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
	
if((dsum < 0) || (sum < 0)) {
fprintf(fp_log,"(1)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
                                        }
                                        if(geometry[i+1][j][k] == OPEN) {
                                                sum -= 1 - (i_trail - i);
						dsum = 1 - (i_trail - i);
//if((i == 105) && (j == 84) && (k == k_mid) && (t > 0.01951240)) {
//fprintf(fp_log,"(2)sum / dsum = %g / dsum\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,dsum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
//if((i == 66) && (j == 111) && (k == 180)) {
//fprintf(fp_log,"(2)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
if((dsum < 0) || (sum < 0)) {
fprintf(fp_log,"(2)sum/dsum = %g/%g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,dsum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
                                        }
// the next two cases are for when the slope of the lip edge is zero
//                                        if(((i == i_pivot[LEFT])||(fabs(di_center[LEFT][CURRENT]) < TOL)) && (geometry[i][j+1][k] == OPEN)) { // a bug here - 12-13-16
                                        if(((i == i_pivot[LEFT])&&(fabs(di_center[LEFT][CURRENT]) < TOL)) && (geometry[i][j+1][k] == OPEN)) { 
                                                sum -= 1 - (j_edge - j);
                                                dsum = 1 - (j_edge - j);
//if((i == 105) && (j == 84) && (k == k_mid) && (t > 0.01951240)) {
//fprintf(fp_log,"(3)sum / dsum = %g / dsum \ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,dsum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
//if((i == 66) && (j == 111) && (k == 180)) {
//fprintf(fp_log,"(3)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
if((dsum < 0) || (sum < 0)) {
fprintf(fp_log,"(3)sum/dsum = %g/%g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,dsum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
                                        }
//                                        else if(((i == i_pivot[LEFT] + 2*i_width[LEFT])||(fabs(di_center[LEFT][CURRENT]) < TOL)) && (geometry[i][j+1][k] == OPEN)) { // a bug here - 12-13-16
                                        else if(((i == i_pivot[LEFT] + 2*i_width[LEFT])&&(fabs(di_center[LEFT][CURRENT]) < TOL)) && (geometry[i][j+1][k] == OPEN)) { 
                                                sum -= dsum = 1 - (j_edge - j);
//if((i == 105) && (j == 84) && (k == k_mid) && (t > 0.01951240)) {
//fprintf(fp_log,"(4)sum / dsum = %g / dsum\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,dsum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
//if((i == 66) && (j == 111) && (k == 180)) {
//fprintf(fp_log,"(4)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
if((dsum < 0) || (sum < 0)) {
fprintf(fp_log,"(4)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
                                        }
// now deal with a sloping lip edge
					else {
					   if(geometry[i][j+1][k] == OPEN) {	
						closer_to = is_closer(i,j);
//						if(closer_to == MIDDLE) {  // must be at the far right edge of lip -- 12-13-16 - looks like this is a bug
						if(j_edge - j < 1) {  // must be at the far right edge of lip
                                                	sum -= dsum = 1 - (j_edge - j);
//if((i == 63) && (j == 110) && (k == 180)) {
//fprintf(fp_log,"(5)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
//if((i == 66) && (j == 111) && (k == 180)) {
//fprintf(fp_log,"(5)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
if((sum < 0) || (dsum < 0)) {
fprintf(fp_log,"(5)dsum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",dsum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
						}
//						else if(closer_to == LEADING_EDGE) {	// this is a bug - fails for a large lip angle
						else if(geometry[i-1][j+1][k] == OPEN) {	// i,j,k must be near an open leading edge
	j_sloping_edge = j_pivot[LEFT]+(i-i_pivot[LEFT])*(j_width[LEFT]+dj_center[LEFT][CURRENT])/di_center[LEFT][CURRENT];      
							if((j_sloping_edge <= j_pivot[LEFT]) || (j_edge < j_sloping_edge) || (j_sloping_edge < j)) {
                                                		sum -= dsum = 1 - (j_edge - j);
//if((i == 63) && (j == 110) && (k == 180)) {
//fprintf(fp_log,"(6)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
//if((i == 66) && (j == 111) && (k == 180)) {
//fprintf(fp_log,"(6)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
if((sum < 0) || (dsum < 0)) {
fprintf(fp_log,"(6)dsum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g/%g\tgeoms %d %d %d %d %d\n",dsum,i,j,k,i_lead,i_trail,j_edge,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
							}
							else {
                                                		sum -= dsum = 1 - (j_sloping_edge - j);
//if((i == 63) && (j == 110) && (k == 180)) {
//fprintf(fp_log,"(7)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
//if((i == 66) && (j == 111) && (k == 180)) {
//fprintf(fp_log,"(7)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
if((sum < 0) || (dsum < 0)) {
fprintf(fp_log,"(7)dsum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g/%g\tgeoms %d %d %d %d %d\n",dsum,i,j,k,i_lead,i_trail,j_edge,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
							}
						}
//						else if(closer_to == TRAILING_EDGE) {	// this is a bug - fails for a large lip angle
						else if(geometry[i+1][j+1][k] == OPEN) {	// should be near an open trailing edge
	j_sloping_edge = j_pivot[LEFT]+(i-i_pivot[LEFT]-2*i_width[LEFT])*(j_width[LEFT]+dj_center[LEFT][CURRENT])/di_center[LEFT][CURRENT];              	
							if((j_sloping_edge <= j_pivot[LEFT]) || (j_edge < j_sloping_edge) || (j_sloping_edge < j)) {

                                                		sum -= dsum = 1 - (j_edge - j);
//if((i == 63) && (j == 110) && (k == 180)) {
//fprintf(fp_log,"(8)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
//if((i == 66) && (j == 111) && (k == 180)) {
//fprintf(fp_log,"(8)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
if((dsum < 0) || (sum < 0)) {
fprintf(fp_log,"(8)dsum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g/%g\tgeoms %d %d %d %d %d\n",dsum,i,j,k,i_lead,i_trail,j_edge,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
							}
							else {
                                                		sum -= dsum = 1 - (j_sloping_edge - j);
//if((i == 63) && (j == 110) && (k == 180)) {
//fprintf(fp_log,"(9)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
//if((i == 66) && (j == 111) && (k == 180)) {
//fprintf(fp_log,"(9)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
if((dsum < 0) || (sum < 0)) {
fprintf(fp_log,"(9)dsum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g/%g\tgeoms %d %d %d %d %d\n",dsum,i,j,k,i_lead,i_trail,j_edge,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
							}
						}
					   }
					   if(geometry[i][j-1][k] == OPEN) {	
						closer_to = is_closer(i,j);
//						if(closer_to == LEADING_EDGE) {
						if((geometry[i][j+1][k] != OPEN) && (di_center[LEFT][CURRENT] > 0.0)) {
	j_sloping_edge = j_pivot[LEFT]+(i-i_pivot[LEFT]-2*i_width[LEFT])*(j_width[LEFT]+dj_center[LEFT][CURRENT])/di_center[LEFT][CURRENT];      
							sum -= dsum = 1 - (j - j_sloping_edge);
//if((i == 63) && (j == 110) && (k == 180)) {
//fprintf(fp_log,"(10.5)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj sloping edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
//if((i == 66) && (j == 111) && (k == 180)) {
//fprintf(fp_log,"(10.5)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj sloping edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
if((dsum < 0) || (sum < 0)) {
fprintf(fp_log,"(10.5)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj sloping edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
						}
						else if((geometry[i-1][j-1][k] == OPEN) && (closer_to == LEADING_EDGE)) {
	j_sloping_edge = j_pivot[LEFT]+(i-i_pivot[LEFT])*(j_width[LEFT]+dj_center[LEFT][CURRENT])/di_center[LEFT][CURRENT];      
// I think this next case will never happen
							if((j_sloping_edge <= j_pivot[LEFT]) || (j_edge < j_sloping_edge) || (j_sloping_edge > j)) {
//                                                		sum -= dsum = 1 - (j - j_edge);
                                                		sum -= dsum = 1 - (j - j_sloping_edge);
//if((i == 105) && (j == 84) && (k == k_mid) && (t > 0.01950)) {
//fprintf(fp_log,"(10)sum / dsum = %g / %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj sloping edge %g\tgeoms %d %d %d %d %d\n",sum,dsum,i,j,k,i_lead,i_trail,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
//if((i == 66) && (j == 111) && (k == 180)) {
//fprintf(fp_log,"(10)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj sloping edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
if((dsum < 0) || (sum < 0)) {
fprintf(fp_log,"(10)dsum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g/%g\tgeoms %d %d %d %d %d\n",dsum,i,j,k,i_lead,i_trail,j_edge,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
							}
							else {
                                                		sum -= dsum = 1 - (j - j_sloping_edge);
//if((i == 63) && (j == 110) && (k == 180)) {
//fprintf(fp_log,"(11)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
//if((i == 66) && (j == 111) && (k == 180)) {
//fprintf(fp_log,"(11)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
if((dsum < 0) || (sum < 0)) {
fprintf(fp_log,"(11)dsum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g/%g\tgeoms %d %d %d %d %d\n",dsum,i,j,k,i_lead,i_trail,j_edge,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
fprintf(fp_log,"\twhich_side = %d\tLEFT/RIGHT %d/%d\n",which_side(i,j),LEFT,RIGHT);
}
							}
						}
//						else if(closer_to == TRAILING_EDGE) {
						else if((geometry[i+1][j-1][k] == OPEN) && (closer_to == TRAILING_EDGE)) {
	j_sloping_edge = j_pivot[LEFT]+(i-i_pivot[LEFT]-2*i_width[LEFT])*(j_width[LEFT]+dj_center[LEFT][CURRENT])/di_center[LEFT][CURRENT];              	
// I think this next case should never happen
							if((j_sloping_edge <= j_pivot[LEFT]) || (j_edge < j_sloping_edge) || (j_sloping_edge > j)) {
                                                		sum -= dsum = 1 - (j - j_edge);
//if((i == 63) && (j == 110) && (k == 180)) {
//fprintf(fp_log,"(12)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
//if((i == 66) && (j == 111) && (k == 180)) {
//fprintf(fp_log,"(12)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
if((dsum < 0) || (sum < 0)) {
fprintf(fp_log,"(12)dsum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g/%g\tgeoms %d %d %d %d %d\n",dsum,i,j,k,i_lead,i_trail,j_edge,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
							}
							else {
                                                		sum -= dsum = 1 - (j - j_sloping_edge);
//if((i == 63) && (j == 110) && (k == 180)) {
//fprintf(fp_log,"(13)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
//if((i == 66) && (j == 111) && (k == 180)) {
//fprintf(fp_log,"(13)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
//}
if((dsum < 0) || (sum < 0)) {
fprintf(fp_log,"(13)dsum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g/%g\tgeoms %d %d %d %d %d\n",dsum,i,j,k,i_lead,i_trail,j_edge,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
							}
						}
					   }
                                        }
                        }
                        if((geometry[i][j][k] == GHOST) && (which_side(i,j) == RIGHT)) {		 // are on the right lip
//if((k == k_mid) && (cell_calc_show_flag == YES)) fprintf(fp_log,"\ncalc cell vals - right lip\t%d / %d / %d\n",i,j,k);
				sum = 4.0;
                                        i_lead = i_leading_edge(RIGHT,j);
                                        i_trail = i_trailing_edge(RIGHT,j);
                                        j_edge = j_center[RIGHT][CURRENT] - j_width[RIGHT] + dj_center[RIGHT][CURRENT];	// change sign of last term 8-22-16
//if((k == k_mid) && (cell_calc_show_flag == YES)) fprintf(fp_log,"\ti_lead / i_trail / j_edge = %g / %g / %g\n",i_lead,i_trail,j_edge);
                                        if(geometry[i-1][j][k] == OPEN) {
                                                sum -= dsum = 1 - (i - i_lead);
//if((k == k_mid) && (cell_calc_show_flag == YES)) fprintf(fp_log,"\topen to back -  sum=%g\n",sum);
//if(dsum < 0) {
if((dsum < 0) || (sum < 0)) {
fprintf(fp_log,"(14)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %d\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
                                        }
                                        if(geometry[i+1][j][k] == OPEN) {
                                                sum -= 1 - (i_trail - i);
                                                dsum = 1 - (i_trail - i);
//if((k == k_mid) && (cell_calc_show_flag == YES)) fprintf(fp_log,"\topen to front -  sum=%g\n",sum);
//if(dsum < 0) {
if((dsum < 0) || (sum < 0)) {
fprintf(fp_log,"(15)sum/dsum = %g/%g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %d\tgeoms %d %d %d %d %d\n",sum,dsum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
                                        }
// the next two cases are for when the slope of the lip edge is zero
//                                        if(((i == i_pivot[RIGHT])||(fabs(di_center[RIGHT][CURRENT])<TOL)) && (geometry[i][j-1][k] == OPEN)) { 
//					if(((i == i_pivot[RIGHT])||(fabs(di_center[RIGHT][CURRENT])<TOL)) && ((geometry[i][j-1][k] == OPEN)||(geometry[i][j+1][k] == OPEN))) { 	- a bug 12-13-16
                                        if(((i == i_pivot[RIGHT])&&(fabs(di_center[RIGHT][CURRENT])<TOL)) && ((geometry[i][j-1][k] == OPEN)||(geometry[i][j+1][k] == OPEN))) { 
//                                                sum -= dsum = 1 - (j - j_edge);
                                                sum -= dsum = 1;
//if((k == k_mid) && (cell_calc_show_flag == YES)) fprintf(fp_log,"\t(1) -  sum=%g\n",sum);
//if(dsum < 0) {
if((dsum < 0) || (sum < 0)) {
fprintf(fp_log,"(16)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
error_flag = YES;
}
                                        }
//                                        else if(((i == i_pivot[RIGHT] + 2*i_width[RIGHT])||(fabs(di_center[RIGHT][CURRENT])< TOL)) && (geometry[i][j-1][k] == OPEN)) { 
//                                        else if(((i == i_pivot[RIGHT] + 2*i_width[RIGHT])||(fabs(di_center[RIGHT][CURRENT])< TOL)) && ((geometry[i][j-1][k] == OPEN)||(geometry[i][j+1][k] == OPEN))) {  // a bug
                                        else if(((i == i_pivot[RIGHT] + 2*i_width[RIGHT])&&(fabs(di_center[RIGHT][CURRENT])< TOL)) && ((geometry[i][j-1][k] == OPEN)||(geometry[i][j+1][k] == OPEN))) { 
                                                sum -= dsum = 1;
//                                                sum -= dsum = 1 - (j - j_edge);
if((dsum < 0) || (sum < 0)) {
fprintf(fp_log,"(17)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
error_flag = YES;
}
                                        }
// now deal with a sloping lip edge
					else {
					   if(geometry[i][j-1][k] == OPEN) {	
						closer_to = is_closer(i,j);
//						if(closer_to == MIDDLE) {  // must be at the far left edge of lip -- 12-13-16 - this looks like a bug
						if(j - j_edge < 1) {  // must be at the far left edge of lip
                                                	sum -= dsum = 1 - (j - j_edge);
if((sum < 0) ||(dsum < 0)) {
fprintf(fp_log,"(18)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %d\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
						}
//						else if(closer_to == LEADING_EDGE) {	// a bug
						else if((closer_to == LEADING_EDGE) || (geometry[i-1][j-1][k] == OPEN)) {	// i,j,k must be near an open leading edge
	j_sloping_edge = j_pivot[RIGHT]-(i-i_pivot[RIGHT])*(j_width[RIGHT]-dj_center[RIGHT][CURRENT])/di_center[RIGHT][CURRENT];      
							if((j_sloping_edge >= j_pivot[RIGHT]) || (j_edge > j_sloping_edge)) {
                                                		sum -= dsum = 1 - (j_edge - j);
if((sum < 0) || (dsum < 0)) {
fprintf(fp_log,"(19)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g/%g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
							}
							else {
                                                		sum -= dsum = 1 - (j_sloping_edge - j);
//if((k == k_mid) && (cell_calc_show_flag == YES)) fprintf(fp_log,"\t(5) -  sum=%g\n",sum);
if(dsum < 0) {
fprintf(fp_log,"(20)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g/%g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
							}
						}
//						else if(closer_to == TRAILING_EDGE) {
						else if((closer_to == TRAILING_EDGE) || (geometry[i+1][j-1][k] == OPEN)) {	// i,j,k must be near an open trailing edge
	j_sloping_edge = j_pivot[RIGHT]-(i-i_pivot[RIGHT]-2*i_width[RIGHT])*(j_width[RIGHT]-dj_center[RIGHT][CURRENT])/di_center[RIGHT][CURRENT];              	
							if((j_sloping_edge >= j_pivot[RIGHT]) || (j_edge > j_sloping_edge)) {
                                                		sum -= dsum = 1 - (j_edge - j);
//if((k == k_mid) && (cell_calc_show_flag == YES)) fprintf(fp_log,"\t(6) -  sum=%g\n",sum);
if(dsum < 0) {
fprintf(fp_log,"(21)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g/%g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
							}
							else {
                                                		sum -= dsum = 1 - (j_sloping_edge - j);
if(dsum < 0) {
fprintf(fp_log,"(22)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g/%g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
							}
						}
					   }
					   if(geometry[i][j+1][k] == OPEN) {	
						closer_to = is_closer(i,j);
//						if(closer_to == LEADING_EDGE) {
						if((geometry[i][j-1][k] != OPEN) && (di_center[RIGHT][CURRENT]) > 0.0) {
	j_sloping_edge = j_pivot[RIGHT]-(i-i_pivot[RIGHT]-2*i_width[RIGHT])*(j_width[RIGHT]-dj_center[RIGHT][CURRENT])/di_center[RIGHT][CURRENT];      
                                                		sum -= dsum = 1 - (j - j_sloping_edge);
if(dsum < 0) {
fprintf(fp_log,"(23.5)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g/%g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
						}
						else if((closer_to == LEADING_EDGE) || (geometry[i-1][j+1][k] == OPEN)) {
	j_sloping_edge = j_pivot[RIGHT]-(i-i_pivot[RIGHT])*(j_width[RIGHT]-dj_center[RIGHT][CURRENT])/di_center[RIGHT][CURRENT];      
							if(((j_sloping_edge >= j_pivot[RIGHT]) || (j_edge > j_sloping_edge) || (j_sloping_edge > j)) && (j-j_edge<1)) {
// I think this case should never happen
                                                		sum -= dsum = 1 - (j - j_edge);
if(dsum < 0) {
fprintf(fp_log,"(23)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g/%g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
							}
							else {
                                                		sum -= dsum = 1 - (j - j_sloping_edge);
if(dsum < 0) {
fprintf(fp_log,"(24)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g/%g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
							}
						}
//						else if(closer_to == TRAILING_EDGE) {
						else if((closer_to == TRAILING_EDGE) && (geometry[i+1][j+1][k] == OPEN)) {
	j_sloping_edge = j_pivot[RIGHT]-(i-i_pivot[RIGHT]-2*i_width[RIGHT])*(j_width[RIGHT]-dj_center[RIGHT][CURRENT])/di_center[RIGHT][CURRENT];              	
							if(((j_sloping_edge >= j_pivot[RIGHT]) || (j_edge > j_sloping_edge) || (j_sloping_edge > j)) && (j-j_edge<1)) {
// I think this case should never happen
                                                		sum -= dsum = 1 - (j - j_edge);
if(dsum < 0) {
fprintf(fp_log,"(25)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g/%g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
							}
							else {
                                                		sum -= dsum = 1 - (j - j_sloping_edge);
if(dsum < 0) {
fprintf(fp_log,"(26)sum = %g\ti/j/k (%d %d %d)\ti lead/trail %g/%g\tj edge %g/%g\tgeoms %d %d %d %d %d\n",sum,i,j,k,i_lead,i_trail,j_edge,j_sloping_edge,geometry[i][j][k],geometry[i-1][j][k],geometry[i+1][j][k],geometry[i][j-1][k],geometry[i][j+1][k]);
}
							}
						}
					   }
                                        }
			}
			site_weight[i][j][k] = sum / 4.0;
			if(site_weight[i][j][k] < 0) {
				error_flag = YES;
				fprintf(fp_log,"\tsite weight = %g\t%d %d %d\tgeom = %d\n",site_weight[i][j][k],i,j,k,geometry[i][j][k]);
                        	if(which_side(i,j) == LEFT) {
					fprintf(fp_log,"\t\tleft: i_lead / trail = %g / %g\tj_edge = %g\n",i_lead,i_trail,j_edge);
                                        fprintf(fp_log,"\t\tj_center = %g\tj_width = %g\tdj = %g\tcloser_to = %d\n",j_center[LEFT][CURRENT],j_width[LEFT],dj_center[LEFT][CURRENT],closer_to);
				}
                        	else if(which_side(i,j) == RIGHT) {
					fprintf(fp_log,"\t\tright: i_lead / trail = %g / %g\tj_edge = %g\n",i_lead,i_trail,j_edge);
                                        fprintf(fp_log,"\t\tj_center = %g\tj_width = %g\tdj = %g\tcloser_to = %d\n",j_center[RIGHT][CURRENT],j_width[RIGHT],dj_center[RIGHT][CURRENT],closer_to);
				}
				else {
					fprintf(fp_log,"\t\twhich side returned %d\n",which_side(i,j));
				}
			}
			if(site_weight[i][j][k] > 1.0) {
				error_flag = YES;
				fprintf(fp_log,"\tsite weight = %g\t%d %d %d\tgeom = %d\n",site_weight[i][j][k],i,j,k,geometry[i][j][k]);
                        	if(which_side(i,j) == LEFT) {
					fprintf(fp_log,"\t\tleft: i_lead / trail = %g / %g\tj_edge = %g\n",i_lead,i_trail,j_edge);
                                        fprintf(fp_log,"\t\tj_center = %g\tj_width = %g\tdj = %g\tcloser_to = %d\n",j_center[LEFT][CURRENT],j_width[LEFT],dj_center[LEFT][CURRENT],closer_to);
				}
                        	else if(which_side(i,j) == RIGHT) {
					fprintf(fp_log,"\t\tright: i_lead / trail = %g / %g\tj_edge = %g\n",i_lead,i_trail,j_edge);
                                        fprintf(fp_log,"\t\tj_center = %g\tj_width = %g\tdj = %g\tcloser_to = %d\n",j_center[RIGHT][CURRENT],j_width[RIGHT],dj_center[RIGHT][CURRENT],closer_to);
				}
				else {
					fprintf(fp_log,"\twhich side returned %d\n",which_side(i,j));
				}
			}
		   }
		}
	}

	if(error_flag == YES) display_cell_values("error in calc weights");

	return(0);
}

/*
 * 	using site weights (level sets) according to Pederzani algorithm
 *
 *	do some diagnostics with variables u_lip_upstream_ave,v_lip_upstream_ave,u_predictor_upstream_ave,v_predictor_upstream_ave;
 *	f_pres_upstream_ave,f_pres_downstream_ave,f_pres_y_ave;
 *
 * 	v2 of this routine to be used when ghost sites are updated like regular open sites
 */
int
update_velocity_on_lip_surfaces2()
{
	int i,j,k,k0;
	int lip_flag;
	double u_lip,v_lip;
	int n;

	k0 = (k_lip_region_min + k_lip_region_max) / 2;
	n = 0;
	u_predictor_upstream_ave = v_predictor_upstream_ave = u_lip_upstream_ave = v_lip_upstream_ave = 0.0;	// for diagnostics
	f_pres_upstream_ave = f_pres_y_ave = 0.0;

	f_pressure_x[LEFT] = f_pressure_x[RIGHT] = f_pressure_y[LEFT] = f_pressure_y[RIGHT] = 0.0;
	for(i = i_lip_region_min; i <= i_lip_region_max; i++) {	
		for(j = j_lip_region_min; j <= j_lip_region_max; j++) {	
			for(k = k_lip_region_min; k <= k_lip_region_max; k++) {	
				if((lip_flag = which_side(i,j)) == LEFT) {
				   u_lip = ((j-j_pivot[LEFT])/(j_center[LEFT][CURRENT] - j_pivot[LEFT])) 
					* dx_grid[i]*(di_center[LEFT][CURRENT]-di_center[LEFT][OLD])/dt;
				   v_lip = ((j-j_pivot[LEFT])/(j_center[LEFT][CURRENT] - j_pivot[LEFT])) 
				   	* dy_grid[j]*(dj_center[LEFT][CURRENT]-dj_center[LEFT][OLD])/dt;
				}
				else {
				   u_lip = ((j_pivot[RIGHT]-j)/(-j_center[RIGHT][CURRENT]+j_pivot[RIGHT])) 
					* dx_grid[i]*(di_center[RIGHT][CURRENT]-di_center[RIGHT][OLD])/dt;
				   v_lip = ((j_pivot[RIGHT]-j)/(-j_center[RIGHT][CURRENT]+j_pivot[RIGHT])) 
				   	* dy_grid[j]*(dj_center[RIGHT][CURRENT]-dj_center[RIGHT][OLD])/dt;
				}
// f_pressure force is calc from all sites in lip - solid and ghost
// but are u_predictor, v_predictor and w_predictor calculated inside the lips?
// I think they should be zero and probably are already
				if(geometry[i][j][k] == GHOST) {
					u_pred_pred[i][j][k] = (1.0-site_weight[i][j][k])*u[i][j][k]
						+ site_weight[i][j][k]*u_lip;
//					f_pressure_x[lip_flag] += site_weight[i][j][k]*(u_lip-u[i][j][k])
//						* (1-site_weight[i][j][k])*(m_cell/dt);
					f_pressure_x[lip_flag] += site_weight[i][j][k]*(u_lip-u[i][j][k])*(m_cell/dt);
					v_pred_pred[i][j][k] = (1.0-site_weight[i][j][k])*v[i][j][k]
						+ site_weight[i][j][k]*v_lip;
//					f_pressure_y[lip_flag] += site_weight[i][j][k]*(v_lip-v[i][j][k])
//						* (1-site_weight[i][j][k])*(m_cell/dt);
					f_pressure_y[lip_flag] += site_weight[i][j][k]*(v_lip-v[i][j][k])*(m_cell/dt);
					w_pred_pred[i][j][k] = (1.0-site_weight[i][j][k])*w[i][j][k];
// consider this change - should go with a corresponding one when pred_pred values are saved 
 					rho_pred_pred[i][j][k] = (1.0-site_weight[i][j][k])*rho[i][j][k];
				}
				else if((geometry[i][j][k] == LEFT_LIP) || (geometry[i][j][k] == RIGHT_LIP)) {
					f_pressure_x[lip_flag] += (u_lip - u_pred_pred[i][j][k])*(m_cell/dt);
					f_pressure_y[lip_flag] += (v_lip - v_pred_pred[i][j][k])*(m_cell/dt);
					u_pred_pred[i][j][k] = u_lip;
					v_pred_pred[i][j][k] = v_lip;
					w_pred_pred[i][j][k] = 0.0; 
					rho_predictor[i][j][k] = 0.0; 
				}
			}
		}
	}

	return(0);
}

/*
 * 	put info on boundary points into log file
 * 	these are points on the boundaries of the instrument
 * 	I don't want boundary points adjacent to lips to be part
 * 	of this list
 */
save_boundary_info()
{
	int i,j,k,n;

	fprintf(fp_log,"boundary points: i,j,k, and boundary flag\n");
	for(n = 0; n < n_boundary; n++) {
		i = x_boundary[n];
		j = y_boundary[n];
		k = z_boundary[n];
		fprintf(fp_log,"%d / %d / %d \t%d\n",i,j,k,boundary_flag[n]);
	}

	return;
}

/*
 * 	calculate how much to adjust dj to avoid lip contact
 * 	make equal adjustments to left and right lips
 * 	minimum lip opening is two grid units
 * 	this give a hard limit to how close the lips can get
 *
 * 	I can't see a simple way to calculate this, so do a simple
 * 	iterative method
 */
double
avoid_j_contact()
{
	double delta;
	double dj_min;
	int j_edge[2];
	double u_lip_left,u_lip_right;	// lip velocities along y in grid units but not time

//	dj_min = 0.00001;

	u_lip_left = 2.0 * (dj_center[LEFT][CURRENT] - dj_center[LEFT][OLD]);
	u_lip_right = 2.0 * (dj_center[RIGHT][CURRENT] - dj_center[RIGHT][OLD]);
	if(fabs(u_lip_left) > fabs(u_lip_right)) {
		dj_min = 0.001 * fabs(u_lip_left);
	}
	else {
		dj_min = 0.001 * fabs(u_lip_right);
	}

	delta = 0.0;

	while(1) {
        	j_edge[LEFT] = j_center[LEFT][CURRENT] + j_width[LEFT] + dj_center[LEFT][CURRENT] - delta;
        	j_edge[RIGHT] = j_center[RIGHT][CURRENT] - j_width[RIGHT] + dj_center[RIGHT][CURRENT] + 1 + delta;
		if(j_edge[RIGHT] - j_edge[LEFT] >= lip_opening_min) break;
		delta += dj_min;
		if(delta >= 1) {
			fprintf(fp_log,"trouble in avoid_j_contact limiting lip motion - delta = %g\n",delta);
			break;
		}
	}
        j_edge[LEFT] = j_center[LEFT][CURRENT] + j_width[LEFT] + dj_center[LEFT][CURRENT];
        j_edge[RIGHT] = j_center[RIGHT][CURRENT] - j_width[RIGHT] + dj_center[RIGHT][CURRENT] + 1;
	fprintf(fp_log,"j center left/right = %d / %d\tdj_min = %g\treturns delta = %g\n",j_edge[LEFT],j_edge[RIGHT],dj_min,delta);

	return(delta);
}

/*	
 *	clear geometry[][][] in lip region 
 */
clear_lip_region()
{
	int i,j,k;

	for(i = i_lip_region_min; i <= i_lip_region_max; i++) {
		for(j = j_lip_region_min+1; j <= j_lip_region_max-1; j++) {
			for(k = k_lip_region_min; k <= k_lip_region_max; k++) {
				geometry[i][j][k] = OPEN;
			}
		}
	}
	return;
}

move_lip2()
{
	double f_drive,amp_drive;

	f_drive = 1500.0;
	f_drive = 800.0;
	amp_drive = 1.1;

	dj_center[LEFT][NEW] = amp_drive * sin(2.0*3.14*f_drive*t);
	dj_center[RIGHT][NEW] = -amp_drive * sin(2.0*3.14*f_drive*t);

	di_center[LEFT][OLD] = di_center[LEFT][CURRENT];
	di_center[LEFT][CURRENT] = di_center[LEFT][NEW];
	dj_center[LEFT][OLD] = dj_center[LEFT][CURRENT];
	dj_center[LEFT][CURRENT] = dj_center[LEFT][NEW];

	di_center[RIGHT][OLD] = di_center[RIGHT][CURRENT];
	di_center[RIGHT][CURRENT] = di_center[RIGHT][NEW];
	dj_center[RIGHT][OLD] = dj_center[RIGHT][CURRENT];
	dj_center[RIGHT][CURRENT] = dj_center[RIGHT][NEW];

	i_center[LEFT][OLD] = i_center[LEFT][CURRENT];
	j_center[LEFT][OLD] = j_center[LEFT][CURRENT];
	i_center[RIGHT][OLD] = i_center[RIGHT][CURRENT];
	j_center[RIGHT][OLD] = j_center[RIGHT][CURRENT];

	i_center[LEFT][CURRENT] = i_origin[LEFT] + di_center[LEFT][CURRENT];
	j_center[LEFT][CURRENT] = j_origin[LEFT] + dj_center[LEFT][CURRENT];
	i_center[RIGHT][CURRENT] = i_origin[RIGHT] + di_center[RIGHT][CURRENT];
	j_center[RIGHT][CURRENT] = j_origin[RIGHT] + dj_center[RIGHT][CURRENT];

	return(0);
}

/*
 *	new version of this routine 09-1-16
 *
 * 	lips have just been moved - now need to remark the sites in geometry[][][]
 * 	to be sure they are current
 *
 * 	need to do this first for the L and R sites (left and right lip regions)
 * 	and then for the ghost cells
 *
 * 	new approach - clear entire lip region and then mark L and R and G sites
 * 	from a fresh start
 */
int
update_lip_geometry_v2(int flag)
{
	int i,j,k,ip,jp;
	int local_i_min,local_i_max;
        double i_lead[2],i_trail[2];
        double i_edge[2],j_edge[2];
	int j_lip_touch;
	int test_flag;

// 	test_flag = NO;

if(flag == VERBOSE) {
display_lip_region("display (5.1) entering update lips");
fflush(fp_log);
}
if(t > 0.05548) {
display_lip_region("display (5.15) entering update lips");
fflush(fp_log);
}

if(flag == VERBOSE) {
fprintf(fp_log,"left: corner %d\tcenter %g\tdj %g\tj_edge %d\n",j_corner[LEFT],j_center[LEFT][CURRENT],dj_center[LEFT][CURRENT],j_edge[LEFT]);
fprintf(fp_log,"right: corner %d\tcenter %g\tdj %g\tj_edge %d\n",j_corner[RIGHT],j_center[RIGHT][CURRENT],dj_center[RIGHT][CURRENT],j_edge[RIGHT]);
fflush(fp_log);
}
// start by clearing geometry[][][] in lip region
	for(i = i_lip_region_min; i <= i_lip_region_max; i++) {
		for(j = j_lip_region_min + 1; j <= j_lip_region_max - 1; j++) {
			for(k = k_lip_region_min; k <= k_lip_region_max; k++) {
				geometry[i][j][k] = OPEN;
			}
		}
	}

// now mark L and R lip sites

        j_edge[LEFT] = j_center[LEFT][CURRENT] + j_width[LEFT] + dj_center[LEFT][CURRENT];
        for(j = j_corner[LEFT]; j <= j_edge[LEFT]; j++) {
		local_i_min = i_leading_edge(LEFT,j) + 1;
		local_i_max = i_trailing_edge(LEFT,j);
		for(i = local_i_min; i <= local_i_max; i++) {
if(t > 0.05548) {
fprintf(fp_log,"\t\ti / j: %d / %d\n",i,j);
fflush(fp_log);
}
			for(k = k_lip_region_min; k <= k_lip_region_max; k++) {
				geometry[i][j][k] = LEFT_LIP;
			}
		}
	}

        j_edge[RIGHT] = j_center[RIGHT][CURRENT] - j_width[RIGHT] + dj_center[RIGHT][CURRENT];
        for(j = j_corner[RIGHT]; j >= j_edge[RIGHT]; j--) {
		local_i_min = i_leading_edge(RIGHT,j) + 1;
		local_i_max = i_trailing_edge(RIGHT,j);
		for(i = local_i_min; i <= local_i_max; i++) {
			for(k = k_lip_region_min; k <= k_lip_region_max; k++) {
				geometry[i][j][k] = RIGHT_LIP;
			}
		}
	}

	if(j_edge[RIGHT] <= j_edge[LEFT] + lip_opening_min) {
		j = nearest_int(j_edge[LEFT]);
		for(i = i_leading_edge(LEFT,(int)j_edge[LEFT]) + 1; i <= i_trailing_edge(LEFT,(int)j_edge[LEFT]); i++) {
			if((i >= i_leading_edge(RIGHT,j) + 1) && (i <= i_trailing_edge(RIGHT,j))) {
				for(k = k_lip_region_min; k <= k_lip_region_max; k++) {
					geometry[i][j][k] = TOUCH;
					u[i][j][k] = 0.0;		// add this so that there is no flow when lips touch
					v[i][j][k] = 0.0;
					w[i][j][k] = 0.0; 
					rho[i][j][k] = 0.0; 
// test_flag = YES;
				}
			}
		}
	}

if(flag == VERBOSE) {
display_lip_region("display (5.3) in update lips after marking both lips");
fflush(fp_log);
}
if(t > 0.05548) {
display_lip_region("display (5.35) update lips after marking both");
fflush(fp_log);
}


	find_ghost_sites(STARTED);

if(flag == VERBOSE) {
display_lip_region("display (5) from update lips after ghost marking");
fflush(fp_log);
}
if(t > 0.05548) {
display_lip_region("display (5.55) entering update lips after ghost marking");
display_cell_values("in update lips");
fflush(fp_log);
}


	return(0);
}

diag_dump(int i,int j,int k)
{

fprintf(fp_log,"\n\tdiag_dump bad at: %d / %d / %d\n",i,j,k);

fprintf(fp_log,"geometries: %d - \t%d\t%d\t%d\t%d\t%d\t%d\n",geometry[i][j][k]
,geometry[i+1][j][k]
,geometry[i-1][j][k]
,geometry[i][j+1][k]
,geometry[i][j-1][k]
,geometry[i][j][k+1]
,geometry[i][j][k-1]);
fprintf(fp_log,"rho / u / v / w: %g \t %g\t%g\t%g\n\n",rho[i][j][k],u[i][j][k],v[i][j][k],w[i][j][k]);
fprintf(fp_log,"at k+1: rho / u / v / w: %g \t %g\t%g\t%g\n\n",rho[i][j][k+1],u[i][j][k+1],v[i][j][k+1],w[i][j][k+1]);

	return(0);
}

check_neighborhood(int i,int j,int k) 
{
	if(geometry[i][j][k+1] == RIGHT_LIP) return(COVERED_BY_LIP);
	if(geometry[i][j][k+1] == LEFT_LIP) return(COVERED_BY_LIP);
	if(geometry[i][j][k-1] == RIGHT_LIP) return(COVERED_BY_LIP);
	if(geometry[i][j][k-1] == LEFT_LIP) return(COVERED_BY_LIP);

	return(NOT_COVERED_BY_LIP);
}


partial_update_lip_geometry_v2(int flag)
{
	int i,j,k,ip,jp;
	int local_i_min,local_i_max;
        double i_lead[2],i_trail[2];
        int i_edge[2],j_edge[2];
	int j_lip_touch;
	int test_flag;

// 	test_flag = NO;

if(flag == VERBOSE) {
display_lip_region("display (5.1) entering update lips");
fflush(fp_log);
}

if(flag == VERBOSE) {
fprintf(fp_log,"left: corner %d\tcenter %g\tdj %g\tj_edge %d\n",j_corner[LEFT],j_center[LEFT][CURRENT],dj_center[LEFT][CURRENT],j_edge[LEFT]);
fprintf(fp_log,"right: corner %d\tcenter %g\tdj %g\tj_edge %d\n",j_corner[RIGHT],j_center[RIGHT][CURRENT],dj_center[RIGHT][CURRENT],j_edge[RIGHT]);
fflush(fp_log);
}
// start by clearing geometry[][][] in lip region
	for(i = i_lip_region_min; i <= i_lip_region_max; i++) {
		for(j = j_lip_region_min + 1; j <= j_lip_region_max - 1; j++) {
			for(k = k_lip_region_min; k <= k_lip_region_max; k++) {
				geometry[i][j][k] = OPEN;
			}
		}
	}

// now mark L and R lip sites

        j_edge[LEFT] = j_center[LEFT][CURRENT] + j_width[LEFT] + dj_center[LEFT][CURRENT];
        for(j = j_corner[LEFT]; j <= j_edge[LEFT]; j++) {
		local_i_min = i_leading_edge(LEFT,j) + 1;
		local_i_max = i_trailing_edge(LEFT,j);
		for(i = local_i_min; i <= local_i_max; i++) {
			for(k = k_lip_region_min; k <= k_lip_region_max; k++) {
				geometry[i][j][k] = LEFT_LIP;
			}
		}
	}

        j_edge[RIGHT] = j_center[RIGHT][CURRENT] - j_width[RIGHT] + dj_center[RIGHT][CURRENT];
        for(j = j_corner[RIGHT]; j >= j_edge[RIGHT]; j--) {
		local_i_min = i_leading_edge(RIGHT,j) + 1;
		local_i_max = i_trailing_edge(RIGHT,j);
		for(i = local_i_min; i <= local_i_max; i++) {
			for(k = k_lip_region_min; k <= k_lip_region_max; k++) {
				geometry[i][j][k] = RIGHT_LIP;
			}
		}
	}

	return(0);
}

/*
 *	similar to routines above but the second argument is a double instead of an int
 */

double
i_leading_edge_double(int flag, double j)
{
        int i;
        double delta_j;
        double di_dj;
        double edge;

        if(flag == LEFT) {
                delta_j = j - j_pivot[LEFT];
                di_dj = di_center[LEFT][CURRENT] / (j_width[LEFT] + dj_center[LEFT][CURRENT]);
                edge = i_corner[LEFT] + delta_j*di_dj;
        }
        else {
                delta_j = j - j_pivot[RIGHT];
                di_dj = -di_center[RIGHT][CURRENT] / (j_width[RIGHT] - dj_center[RIGHT][CURRENT]);
                edge = i_corner[RIGHT] + delta_j*di_dj;
        }

        return(edge);
}

double
i_trailing_edge_double(int flag, double j)
{
        int i;
        double delta_j;
        double di_dj;
        double edge;

        if(flag == LEFT) {
                delta_j = j - j_pivot[LEFT];
                di_dj = di_center[LEFT][CURRENT] / (j_width[LEFT] + dj_center[LEFT][CURRENT]);
                edge = i_corner[LEFT] + 2*i_width[LEFT] + delta_j*di_dj;
        }
        else {
                delta_j = j - j_pivot[RIGHT];
                di_dj = -di_center[RIGHT][CURRENT] / (j_width[RIGHT] - dj_center[RIGHT][CURRENT]);
                edge = i_corner[RIGHT] + 2*i_width[RIGHT] + delta_j*di_dj;
 	}

        return(edge);
}

/*
 * return the i index of the current middle of the lip 
 * flag = LEFT or RIGHT
 */
int
i_mid_lip(int flag)
{
	int i_mid;

	i_mid = i_origin[flag] + 2.0 * di_center[flag][CURRENT];

// fprintf(fp_log,"\ti_mid = %d\n",i_mid);

	return(i_mid);
}

/*
 * return the i index of the current lip entrance 
 */
int
i_entrance_lip(int flag)
{
	int i_entrance;

	i_entrance = i_origin[flag] - i_width[flag] + 2.0 * di_center[flag][CURRENT]; 

// fprintf(fp_log,"\ti_entrance = %d\n",i_entrance);

	return(i_entrance);
}

/*
 * return the i index of the current lip exit 
 */
int
i_exit_lip(int flag)
{
	int i_exit;

	i_exit = i_origin[flag] + i_width[flag] + 2.0 * di_center[flag][CURRENT]; 

// fprintf(fp_log,"\ti_exit = %d\n",i_exit);

	return(i_exit);
}

/*
 * return the i index of the middle of the upstream edge of a lip 
 */
int
i_upstream_lip_middle(int flag)
{
	int i_upstream;

	i_upstream = i_origin[flag] - i_width[flag] + di_center[flag][CURRENT]; 

	return(i_upstream);
}

/*
 * return the i index of the middle of the downstream edge of a lip 
 */
int
i_downstream_lip_middle(int flag)
{
	int i_downstream;

	i_downstream = i_origin[flag] + i_width[flag] + di_center[flag][CURRENT]; 

	return(i_downstream);
}

